<style type="text/css">
input:focus, select:focus, textarea:focus, button:focus {
    outline: none;
}

body {
    position: absolute;
    top: 0;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    font-family: helvetica, sans-serif;
    margin: 0;
    padding: 0;
    background-color: white;
}

#all_pt_n2_content_div {
    position: absolute;
    width: 100vw;
    z-index: 5;
}

#ptN2ContentDivId {
    display: flex;
    flex: 0 0 auto;
}

#d3_content_div {
    display: flex;
    flex: auto;
    height: 100vh;
    align-items: flex-start;
    justify-content: baseline;
    overflow: auto;
    position: relative;
    margin-left: -75px;
    transition: margin-left 0.4s;
}

#svgDiv {
    position: absolute;
    top: 5px;
    left: 30px;
    z-index: 2;
    display: flex;
    /* flex: 0 0 auto; */
    /* resize: both; */
    overflow: visible;
}

#svgId {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    flex: 0 0 auto;
    transform-origin: 0 0;
}

#n2-resizer-box {
    position: absolute;
    right: -3px;
}

.inactive-resizer-box {
    visibility: visible;
    left: auto;
    border: 3px solid transparent;
    pointer-events: none;
}

.active-resizer-box {
    left: -3px;
    visibility: visible;
    border: 3px dashed #98daba;
    pointer-events: initial;
}

.hidden-resizer-box {
    visibility: hidden;
}

#n2-resizer-handle {
    position: absolute;
    right: -2px;
    bottom: 0px;
    margin: 0;
    height: 18px;
    cursor: nwse-resize;
    pointer-events: initial;
    overflow: hidden;
}

.inactive-resizer-handle::before {
    content: '\25a8';
}

.inactive-resizer-handle {
    background: linear-gradient(135deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 54%, rgba(255, 255, 255, 1) 55%, rgba(255, 255, 255, 1) 100%);
    font-size: 20px;
    border: 0;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    -moz-background-clip: text;
    -moz-text-fill-color: transparent;
    font-weight: bold;
    text-align: right;
    vertical-align: bottom;
    width: 18px;
    padding: 0;
}

.active-resizer-handle {
    background: #98daba;
    border: 1px solid #98daba;
    border-bottom-right-radius: 0;
    color: #006000;
    font-size: 9pt;
    align-items: center;
    display: flex;
    width: auto;
    padding: 1px 5px 1px 5px;
}

/* The Modal (background) */

.modal {
    display: none;
    /* Hidden by default */
    position: fixed;
    /* Stay in place */
    z-index: 9999;
    /* Sit on top */
    padding-top: 10px;
    /* Location of the box */
    left: 0;
    top: 0;
    width: 100%;
    /* Full width */
    height: 100%;
    /* Full height */
    overflow: auto;
    /* Enable scroll if needed */
    background-color: rgb(0, 0, 0);
    /* Fallback color */
    background-color: rgba(0, 0, 0, 0.4);
    /* Black w/ opacity */
}

/* Modal Content */

.modal-content {
    font-family: helvetica, sans-serif;
    font-size: 14px;
    position: relative;
    background-color: #fefefe;
    margin: 10px 100px 10px 100px;
    padding: 0;
    border: 1px solid #888;
    width: auto;
    min-width: 950px;
    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    -webkit-animation-name: animatetop;
    -webkit-animation-duration: 0.4s;
    animation-name: animatetop;
    animation-duration: 0.4s;
}

@font-face {
    /* Subset of fonts from Font Awesome v4.6.3 created using http://fontello.com/ */
    font-family: 'fontello';
    src: url('data:application/font-woff;charset=utf-8;base64,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') format('woff');
}

.context-menu {
    display: none;
    position: absolute;
    z-index: 10;
    padding: 12px 0;
    width: 240px;
    background-color: #fff;
    border: solid 1px #dfdfdf;
    box-shadow: 1px 1px 2px #cfcfcf;
}

.context-menu--active {
    display: block;
}

.context-menu__items {
    list-style: none;
    margin: 0;
    padding: 0;
}

.context-menu__item {
    display: block;
    margin-bottom: 4px;
}

.context-menu__item:last-child {
    margin-bottom: 0;
}

.context-menu__link {
    display: block;
    padding: 4px 12px;
    color: #0066aa;
    text-decoration: none;
}

.context-menu__link:hover {
    color: #fff;
    background-color: #0066aa;
}

.tool-tip {
    z-index: 10;
    font-size: 11px;
    padding: 5;
    background-color: #fff;
    border: solid 1px #dfdfdf;
}

div.offgrid {
    z-index: 10;
    font-size: 11px;
    padding: 5;
    background-color: #fff;
    border: solid 1px #dfdfdf;
    position: absolute;
    opacity: 0.7;
}

/* The Close Button */

.close {
    color: white;
    float: right;
    font-size: 28px;
    font-weight: bold;
}

.close:hover, .close:focus {
    color: #000;
    text-decoration: none;
    cursor: pointer;
}

.modal-header {
    font-family: helvetica, sans-serif;
    font-size: 20px;
    padding: 2px 16px;
    background-color: steelblue;
    color: white;
    margin: 2px;
    padding: 10px;
}

.modal-body {
    padding: 2px 16px;
}

.modal-footer {
    font-family: helvetica, sans-serif;
    font-size: 12px;
    padding: 2px 16px;
    background-color: steelblue;
    color: white;
    margin: 2px;
    padding: 10px;
}

.modal-section-header {
    font-size: 30px;
    font-weight: bold;
    padding: 0px 20px;
}

.toolbar-help {
    width: auto;
    height: auto;
    padding: 0px 20px;
}

#logo-container {
    position: absolute;
    width: 70px;
    height: 60px;
    border-radius: 35px;
    background-color: white;
    opacity: 30%;
    bottom: 15px;
    right: 15px;
    z-index: 15;
    pointer-events: none;
}

#company-logo {
    position: absolute;
    max-width: 50px;
    height: 30px;
    left: 50%;
    margin-left: -25px;
    top: 50%;
    margin-top: -15px;
    pointer-events: none;
}

rect.diagHighlight {
    fill: black !important;
}

rect.inputHighlight {
    fill: salmon !important;
}

rect.outputHighlight {
    fill: seagreen !important;
}

.no-show {
    display: none;
}

.show {
    display: block;
}

#waiting-icon {
    position: absolute;
    width: 200px;
    height: 200px;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    opacity: .7;
}

#waiting-container {
    width: 100vw;
    height: 100vh;
    position: relative;
    z-index: 99;
    background: none;
}
</style>


<style type="text/css">
/******************* Icon styling *******************/

/*
Instructions on editing the icons used for the toolbar.

	1. Go to https://icomoon.io/app/#/select
	2. In the top left corner press import icons and select all the icons in
		the openmdao/visualization/n2_viewer/assets/toolbar_graphics/icomoon_icons/SVG folder
	4. Depending on whether you want to remove, replace, or edit an icon:
		- If you want to remove an icon, in the icomoon toolbar there should be a trash icon.
			Click that and then click the icon you wish to remove. Click the Select button in the icomoon toolbar
			if you are finished removing icons to go back to selection mode.
		- If you want to make a new icon, you need to use either Sketch or Adobe Illustrator, or any other SVG editing
			tool and make a new SVG file. Then using the hamburger menu on the icomoon site, select Import to Set and
			select your new SVG file.
		- If you want to modify an icon, edit the existing SVG file located
			in openmdao/visualization/n2_viewer/assets/toolbar_graphics/icomoon_icons/SVG. Be sure to keep the same
			name of the file
			Then on the icomoon site, press on the hamburger menu on the right side and select Import to Set.
			Select the modified SVG file.
			A dialog will popup asking Replace existing icons?. Click the Replace button.
			This process will overwrite the existing icon on the icomoon site with the imported one.
	5. Once you have made all the changes you wish to make, you need to select all the icons by using the hamburger
		menu and clicking Select All, then in the bottom right corner press Generate Font.
		Then press Download in the bottom right
	6. Save the zip file and unzip it
	7. If you added or removed any icons, you need to update the icomoon section of this css file. See the next
		section. Open up the style.css file downloaded from icomoon. Copy everything except the @font-face part of that
		file. Paste that into the contents of the icomoon section of this file replacing it.
	8. Replace the existing openmdao/visualization/n2_viewer/style/icomoon.woff file with the one in the zip file
		downloaded from icomoon.
	9. If you want the icons in a format other than SVG, from the icomoon Web app page, click Generate SVG & More.
		From the page that is then displayed, click the gear icon in lower left next to the Download button. In the
		window that comes up, select the formats you want and close the window. Click the Download button. 
*/

/* Beginning of section is copied from the icomoon style.css file that is generated by icomoon and is contained in the zip
	file that is downloaded from icomoon
 */
[class^='icon-'],
[class*=' icon-'] {
	/* use !important to prevent issues with browser extensions that change fonts */
	font-family: 'icomoon' !important;
	speak: none;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	line-height: 1;

	/* Better Font Rendering =========== */
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.icon-question-circle:before {
	content: '\e90d';
}

.icon-bezier-curve:before {
	content: '\e908';
}

.icon-caret-right:before {
	content: '\e909';
}

.icon-chevron-left:before {
	content: '\e90a';
}

.icon-info-circle:before {
	content: '\e90b';
}

.icon-key:before {
	content: '\e90c';
}

.icon-save:before {
	content: '\e90e';
}

.icon-forward:before {
	content: '\e906';
}

.icon-forward {
	font-size: 13px !important;
}

.icon-backward:before {
	content: '\e907';
}

.icon-backward {
	font-size: 13px !important;
}

.icon-collapse-depth:before {
	content: '\e905';
}

.icon-hide-connections:before {
	content: '\e900';
}

.icon-hide-connections-2:before {
	content: '\e900';
}

.icon-linear-solver:before {
	content: '\e901';
}

.icon-model-height:before {
	content: '\e902';
}

.icon-nonlinear-solver:before {
	content: '\e903';
}

.icon-show-connections:before {
	content: '\e904';
}

.icon-show-connections-2:before {
	content: '\e904';
}

.icon-home2:before {
	content: '\e912';
}

.icon-floppy-disk:before {
	content: '\e962';
}

.icon-search:before {
	content: '\e986';
}

.icon-enlarge:before {
	content: '\e989';
}

.icon-shrink:before {
	content: '\e98a';
}

.icon-enlarge2:before {
	content: '\e98b';
}

.icon-shrink2:before {
	content: '\e98c';
}

.icon-text-height:before {
	content: '\ea5f';
}

/* End of section is copied from the icomoon style.css file that is generated by icomoon */


[class^='icon-']:before,
[class*=' icon-']:before {
	display: inline-block;
	font: normal normal normal 14px/1 fontello;
	font-size: inherit;
	text-rendering: auto;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* makes the font 33%% larger relative to the icon container */
.bigger-font {
	font-size: 1.33333333em;
	line-height: 0.75em;
	vertical-align: -15%;
}

/* To get SVG and PNG images of these icon fonts, use https://icomoon.io/app/#/select */
.icon-home:before {
	content: '\e800';
}

.icon-left-big:before {
	content: '\e801';
}

.icon-right-big:before {
	content: '\e802';
}

.icon-up-big:before {
	content: '\e803';
}

.icon-resize-full:before {
	content: '\e804';
}

.icon-resize-small:before {
	content: '\e805';
}

.icon-resize-vertical:before {
	content: '\e807';
}

.icon-floppy:before {
	content: '\e808';
}

.icon-minus:before {
	content: '\e80a';
}

.icon-exchange:before {
	content: '\f0ec';
}

.icon-terminal:before {
	content: '\f120';
}

.icon-help:before {
	content: '\f128';
}

.icon-eraser:before {
	content: '\f12d';
}

.icon-sort-number-up:before {
	content: '\f162';
}

.icon-right:before {
	content: '\f178';
}

.icon-map-signs:before {
	content: '\f277';
}

</style>


<style type="text/css">
/******************* Toolbar styling *******************/

/* Search Bar */

#searchbar-container {
    align-self: flex-start;
    display: flex;
    align-items: center;
    flex-direction: row;
    margin-left: 12px;
    margin-bottom: 20px;
    z-index: 20;
    overflow: visible;
    height: 40px;
}

.search-button {
    background-color: rgba(0, 0, 0, 0);
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    border-radius: 4px;
    border: 1px solid #aaa;
    display: inline-block;
    cursor: pointer;
    color: #666666;
    font-size: 16px;
    text-align: center;
    text-decoration: none;
    width: 30px;
    max-width: 30px;
    height: 50px;
    max-height: 50px;
    margin: 30px 1px 2px 1px;
    border: 0px solid rgba(0, 0, 0, 0);
}

#searchbar-and-label {
    display: flex;
    flex-direction: column;
    margin-bottom: -10px;
}

.searchbar {
    width: 100%;
    display: flex;
    transition: border-color 0.5s, width 0.5s, margin-left 0.5s;
    margin-left: 8px;
    display: block;
    border: 1px solid rgba(0, 0, 0, 0);
    background-color: white;
    border-top-right-radius: 25px;
    border-bottom-right-radius: 25px;
    padding: 8px 8px;
    /* transition-delay: 0.5s; */
    transition: border-color 0.5s, width 0.5s, margin-left 0.5s, visibility 0.5s;
}

.searchbar:focus {
    background: lightcyan;
}

.searchbar-hidden {
    overflow: hidden;
    visibility: hidden;
    width: 0px;
    transition: border-color 0.5s, width 0.5s, margin-left 0.5s, visibility 0.5s;
}

.searchbar-visible {
    overflow: visible;
    visibility: visible;
    width: 200px;
    transition: border-color 0.5s, width 0.5s, margin-left 0.5s, visibility 0.5s;
}

.searchbar-visible .searchbar {
    border-color: #03793f;
}

.searchbar-container label { 
    font-size: 10pt;
    color: black;
    margin-left: 8px;
    transition: font-size 0.2s;
    transition-delay: 0.5s;
    width: 200px;
}

/* Toolbar Container*/

#toolbarLoc {
    margin: 0;
    padding: 0;
    height: 615px;
    width: 65px;
    border-bottom-right-radius: 15px;
    position: relative;
    box-shadow: 20px 0px 35px rgba(0, 0, 0, 0.1);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    left: -65px;
    /* Start hidden */
    transition: left 0.5s;
    z-index: 5;
    border-right: 1px solid gray;
    border-bottom: 1px solid gray;
}

.toolbar {
    display: flex;
    width: 100%;
    flex-direction: column;
    align-self: flex-start;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0;
    cursor: pointer;
    position: relative;
}

.toolbar-hide-container {
    background-color: white;
    width: 15px;
    height: 35px;
    border-top-right-radius: 25%;
    border-bottom-right-radius: 25%;

    position: absolute;
    top: 270px;
    margin-left: 20px;
    left: -20px;
    /* Start hidden */
    display: flex;
    align-items: center;
    justify-content: flex-end;
    cursor: pointer;
    z-index: 30;
    transition: left 0.5s, transform 0.5s;
    border-top: 1px solid gray;
    border-right: 1px solid gray;
    border-bottom: 1px solid gray;
}

.toolbar-hide-container:hover>.hide-toolbar-button {
    color: green;
    transform: scale(1.25);
}

.toolbar-hide-container i {
    color: black;
    margin-right: 5px;
    cursor: pointer;
    transform: rotate(-180deg);
    /* Start hidden */
    transition: color 0.4s, transform 0.4s;
    font-size: 12px;
}

.toolbar-group-expandable {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    width: 0px;
    padding: 2px 10px;
    border-top-right-radius: 20px;
    border-bottom-right-radius: 20px;
    align-items: center;
    max-width: 0;
    opacity: 0;
    min-height: 100%;
    transition: opacity 1s, max-width 1s;

}

.toolbar-group-expandable p {
    text-align: center;
    color: white;
    font-size: 10px;
    margin: 0;
}

.toolbar-group {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 50px;
    border-bottom-left-radius: 15px;
    border-bottom-right-radius: 15px;
    border-top-right-radius: 10px;
    border-top-left-radius: 10px;
    position: relative;
}

.expandable:hover>.toolbar-group-expandable {
    opacity: 1;
    width: auto;
    max-width: 200px;
    transition: opacity 1s, max-width 1s;
    pointer-events: initial;
}

.expandable {
    display: flex;
    flex-direction: row;
    align-self: flex-start;
    align-items: center;
}

.expandable i:first-of-type {
    margin-left: 15px;
}

.expandable>.toolbar-group-expandable {
    pointer-events: none;
}

/* Toolbar Groups */

.group-1 {
    background-color: #98daba;
    padding: 10px 0;
    z-index: 5;
}

.group-2 {
    background-color: #7dcda6;
    padding: 20px 0 5px 0;
    margin-top: -20px;
    z-index: 4;
    flex-direction: row;
    align-items: center;
}

.group-3 {
    background-color: #66b48e;
    padding: 20px 0 5px 0;
    margin-top: -20px;
    z-index: 3;
    height: 120px;
}

.group-4 {
    background-color: #42926b;
    padding: 20px 0 5px 0;
    margin-top: -20px;
    z-index: 2;
}

.group-5 {
    background-color: #30684d;
    padding: 20px 0 7px 0;
    margin-top: -20px;
    z-index: 1;
}

#collapse-expandable {
    background-color: #7dcda6;
}

#connections-expandable {
    background-color: #66b48e;
}

#solvers-expandable {
    background-color: #66b48e;
}

#text-width-expandable {
    background-color: #42926b;
    display: flex;
    align-items: center;
}

#text-width-expandable p {
    color: white;
    margin-left: 5px;
    width: 20px;
    font-weight: 600;
}

#model-height-expandable {
    background-color: #42926b;
    display: flex;
    align-items: center;
}

#model-height-expandable p {
    color: white;
    margin-left: 5px;
    width: 20px;
    font-weight: 600;
}

#model-depth-expandable {
    background-color: #42926b;
    display: flex;
    align-items: center;
}

#model-depth-expandable p {
    color: white;
    margin-left: 5px;
    width: 20px;
    font-weight: 600;
}

#depth-slider {
    -webkit-transform: rotate(-180deg);
    -moz-transform: rotate(-180deg);
    transform: rotate(-180deg);
}

/* Icon Styling */

.toolbar-group-expandable i {
    padding: 0px 8px;
}

.icon-search {
    color: #78d3a6;
    font-size: 24px;
}

.toolbar .fas {
    margin: 7px 0;
    color: white;
    font-size: 20px;
    cursor: pointer;
    transition: color 0.2s;
}

.solver-button {
    font-size: 25px !important;
}

.active-tab-icon {
    color: #00ff00 !important;
}

.toolbar .fas:hover {
    color: #aeffa4;
}

.caret {
    opacity: 1;
    color: white !important;
    font-size: 15px !important;
    margin-left: 5px !important;
    transform: rotate('0deg');
    transition: transform 0.4s, opacity 0.4s;
}

.expandable:hover>.caret {
    transform: rotate(-180deg);
    opacity: 0.5;
    transition: transform 0.4s, opacity 0.4s;
}

#info-button {
    font-size: 30px !important;
    color: white;
    opacity: 1;
    transition: opacity 0.5s, color 0.5s;
}

#info-button:hover {
    opacity: 0.7;
}

#question-button {
    font-size: 30px !important;
    opacity: 1;
    color: white;
}

#question-button:hover {
    opacity: 0.7;
}

/* Slider */

.slider {
    -webkit-appearance: none;
    width: 100px;
    height: 8px;
    border-radius: 5px;
    background: white;
    outline: none;
    opacity: 0.7;
    -webkit-transition: 0.2s;
    transition: opacity 0.2s, background 0.3s;
    margin: 10px 0;
}

.slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #98daba;
    cursor: pointer;
}

.slider::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: #98daba;
    cursor: pointer;
}

.slider datalist {
    color: white;
    display: flex;
}

#model-slider-label {
    min-width: 30px;
    text-align: center;
}

#model-slider-fit {
    color: white;
    background: #42926b;
    border-radius: 40%;
    border: 1px solid white;
    padding: 5px;
    font-weight: 600;
    margin-left: 5px;
    -webkit-transition: 0.2s;
    transition: opacity 0.2s, background 0.3s;
}

#model-slider-fit:active {
    background: #264c39;
}

.disabled-button {
    color: #66b48e !important;
}

</style>


<style type="text/css">
/******************* Node Data styling *******************/
#node-info-container {
    position: absolute;
    z-index: 10;
    height: auto;
}

#node-info-table {
	overflow: hidden;
	background-color: white;
	border-radius: 10px;
	border: 1px solid #a0a0a0;
    transition: opacity 0.25s;
    box-shadow: 3px 3px 3px 1px rgba(0, 0, 0, 0.2);
    min-width: 200px;
    border-collapse: separate;
    opacity: .95;
}

.info-hidden {
    visibility: hidden;
}

.info-visible {
    visibility: visible;
}

#node-info-table thead th {
    background-color: #42926b;
    color: black;
    padding: 5px;
    font-size: 11pt;
}

#node-info-table tbody th {
    text-align: right;
    font-size: 9pt;
    margin-top: 0;
    border-top: 0;
    border-bottom: 1px solid #a0a0a0;
    border-right: 1px solid #a0a0a0;
    padding: 3px;
    white-space: nowrap;
}

#node-info-table tbody td {
    text-align: left;
    font-size: 9pt;
    margin-top: 0;
    margin-left: 0;
    border-top: 0;
    border-left: 0;
    border-bottom: 1px solid #a0a0a0;
    padding: 3px;
    white-space: nowrap;
}

#node-info-table tfoot th {
    background-color: #42926b;
    padding: 2px;
    font-size: 11pt;
}

.caps {
    text-transform: capitalize;
}

.info-header {
	background-color: #42926b;
}

.info-header p {
	color: white;
	text-align: center;
}

.node-data-cursor {
    cursor: context-menu;
}

#node-info-pin {
    position: absolute;
    top: 5px;
    right: 8px;
    cursor: pointer;
    padding: 0;
    margin: 0;
    border: 0;
    font-size: 12px;
    background: #ccc;
    width: 18px;
    height: 18px;
    padding: 0 2px 0 2px;
    /* box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.2); */
    border-radius: 3px;
}

#node-info-pin:hover {
    top: 4px;
    right: 9px;
    box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.2);
}
</style>


<style type="text/css">
/******************* Legend styling *******************/

#legend-div {
    position: absolute;
    left: 50px;
    bottom: 10px;
    z-index: 2;
    visibility: hidden;
    display: flex;
    flex-direction: row;
    border-radius: 15px;
    cursor: grab;
    opacity: 0.95;
    box-shadow: 3px 3px 3px 1px rgba(0, 0, 0, 0.2);
}

.legend-box-container {
    display: flex;
    align-items: center;
    margin-left: 15px;
}

.legend-box-container p {
    display: flex;
    font-size: 14px;
    margin-left: 4px;
    white-space: nowrap;
}

.legend-box {
    display: flex;
    width: 12px;
    height: 12px;
    border-radius: 2px;
}

.legend-title-container {
    height: 100%;
    width: 40px;
    display: inline-block;
    background-color: #42926b;
    overflow: visible;
}

.legend-title {
    text-align: center;
    font-weight: bold;
    vertical-align: middle;
    width: 90px;
    height: 40px;
    font-size: 14px;
    color: white;
    position: relative;
    transform-origin: 0 0;
    transform: rotate(-90deg) translate(-77px, 3px);
}

.sys-var-container::-webkit-scrollbar, .linear-solvers-container::-webkit-scrollbar, .n2-symbols-container::-webkit-scrollbar {
    display: none;
}

/* Systems and Varaibles Container */

.sys-var-container {
    height: 90px;
    border-radius: 15px;
    border: 1px solid #98daba;
    display: flex;
    flex-direction: row;
    background-color: white;
    z-index: 1;
    overflow-y: scroll;
}

#sys-var-legend {
    height: 90px;
    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
    margin-right: 45px;
    overflow-x: hidden;
}

/* N2 Symbols Group */

.n2-symbols-container {
    height: 90px;
    min-height: 45px;
    border-radius: 15px;
    border: 1px solid #66b48e;
    display: flex;
    align-items: center;
    padding-right: 45px;
    background-color: white;
    z-index: 2;
    overflow: scroll;
    margin-left: -20px;
}

#symbols-legend {
    display: flex;
    width: auto;
    flex-direction: column;
    padding-left: 8px;
}

.symbol {
    display: flex;
    align-items: center;
    margin: 2px 0;
}

.symbol p {
    font-size: 14px;
    margin: 0;
    margin-left: 8px;
    white-space: nowrap;
}

.symbol-outer {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 18px;
    height: 18px;
}

.symbol-inner {
    position: absolute;
    margin: 0 auto;
}

.scalar {
    border: 2px solid #cecece;
}

.scalar .symbol-inner {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background-color: #9fc4c6;
}

.vector {
    border: 2px solid #cecece;
}

.vector .symbol-inner {
    width: 12px;
    height: 12px;
    background-color: #9fc4c6;
}

.collapsed {
    border: 2px solid #9fc4c6;
}

.collapsed .symbol-inner {
    width: 12px;
    height: 12px;
    background-color: #9fc4c6;
}

/* Linear Solvers Group */

.linear-solvers-container {
    height: 90px;
    border-radius: 15px;
    border: 1px solid #42926b;
    display: flex;
    flex-direction: row;
    margin-left: -20px;
    margin-right: 0;
    background-color: white;
    z-index: 3;
    overflow-y: scroll;
}

#solvers-legend {
    height: 90px;
    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
    margin-right: 20px;
    overflow-x: hidden;
}

.draggable {
    position: absolute;
    width: 100px;
    height: 20px;
    left: 50%;
    background-color: #42926b;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
    display: flex;
    justify-content: center;
    align-items: center;
    transform: translate(-50%, -20px)
}

.draggable>.icon-key {
    color: white;
}

#draggable-legend-dots p {
    color: white;
    padding-left: 5px;
    padding-right: 5px;
}

#close-legend {
    position: absolute;
    top: -20px;
    right: -18px;
    height: 20px;
    width: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 4;
    cursor: default;
}

#close-legend p::before {
    content: '\2715'
}

#close-legend p {
    color: black;
    font-weight: bold;
    font-size: 20px;
    text-align: center;
    margin: auto;
    vertical-align: middle;
    width: 20px;
    height: 20px;
}

p.legend-dots::before {
    content: '\A789\A789\A789\A789\A789\A789';
}
</style>


<style type="text/css">
[hidden] {
    display: none;
}

.visually-hidden {
    position: absolute;
    clip: rect(0, 0, 0, 0);
}

div.awesomplete {
    display: inline-block;
    position: relative;
}

div.awesomplete>input {}

div.awesomplete>ul {
    position: absolute;
    z-index: 10;
    min-width: 100%;
    box-sizing: border-box;
    list-style: none;
    padding: 5px;
    margin: 0 0 0 8px;
    background: lightgray;
    opacity: .85;
    border: 1px solid rgba(0, 0, 0, .3);
    box-shadow: .05em .2em .6em rgba(0, 0, 0, .2);
    text-shadow: none;
    font-size: 10pt;
    border-bottom-left-radius: 5px;
    border-bottom-right-radius: 5px;
}

div.awesomplete>ul[hidden],
div.awesomplete>ul:empty {
    display: none;
}

@supports (transform: scale(0)) {
    div.awesomplete>ul {
        transition: .3s cubic-bezier(.4, .2, .5, 1.4);
        transform-origin: 1.43em -.43em;
    }

    div.awesomplete>ul[hidden],
    div.awesomplete>ul:empty {
        opacity: 0;
        transform: scale(0);
        display: block;
        transition-timing-function: ease;
    }
}

/* Pointer
	div.awesomplete > ul:before {
		content: "";
		position: absolute;
		top: -.43em;
		left: 1em;
		width: 0; height: 0;
		padding: .4em;
		background: white;
		border: inherit;
		border-right: 0;
		border-bottom: 0;
		-webkit-transform: rotate(45deg);
		transform: rotate(45deg);
	}*/

div.awesomplete>ul>li {
    position: relative;
    padding: .2em .5em;
    cursor: pointer;
}

div.awesomplete>ul>li:hover {
    background: hsl(200, 40%, 80%);
    color: black;
}

div.awesomplete>ul>li[aria-selected="true"] {
    background: hsl(205, 40%, 40%);
    color: white;
}

div.awesomplete mark {
    /* background: hsl(65, 100%, 50%); */
    background: cyan;
}

div.awesomplete li:hover mark {
    /* background: hsl(68, 100%, 41%); */
    background: cyan;
}

div.awesomplete li[aria-selected="true"] mark {
    background: hsl(86, 100%, 21%);
    color: inherit;
}
</style>


<div id="all_pt_n2_content_div" class="embedded-n2">
    <div id="ptN2ContentDivId">
        <!-- The Model -->
        <div class="modal" id="myModal"><div class="modal-content"><div class="modal-header"><span class="close" id="idSpanModalClose">&times;</span>
Instructions</div>

<div class="modal-body"><p >Left clicking on a node in the partition tree will navigate to that node. Right clicking on a node in the model hierarchy will collapse/expand it. A click on any element in the N2 diagram will allow those arrows to persist.</p>
</div>

<div class="modal-section-header">Toolbar Help</div>

<div class="toolbar-help"><?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   sodipodi:docname="toolbar_help.svg"
   inkscape:version="1.0 (4035a4f, 2020-05-01)"
   id="svg489"
   version="1.1"
   viewBox="0 0 362.25361 250.11945"
   height="625.29865"
   width="905.63403">
  <defs
     id="defs483">
    <marker
       inkscape:isstock="true"
       style="overflow:visible;"
       id="marker3367"
       refX="0.0"
       refY="0.0"
       orient="auto"
       inkscape:stockid="Arrow2Lend">
      <path
         transform="scale(1.1) rotate(180) translate(1,0)"
         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
         id="path3365" />
    </marker>
    <marker
       inkscape:isstock="true"
       style="overflow:visible;"
       id="marker3357"
       refX="0.0"
       refY="0.0"
       orient="auto"
       inkscape:stockid="Arrow2Lend">
      <path
         transform="scale(1.1) rotate(180) translate(1,0)"
         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
         id="path3355" />
    </marker>
    <marker
       inkscape:stockid="Arrow2Lend"
       orient="auto"
       refY="0.0"
       refX="0.0"
       id="marker3033"
       style="overflow:visible;"
       inkscape:isstock="true"
       inkscape:collect="always">
      <path
         id="path3031"
         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
         transform="scale(1.1) rotate(180) translate(1,0)" />
    </marker>
    <marker
       inkscape:stockid="Arrow2Lend"
       orient="auto"
       refY="0.0"
       refX="0.0"
       id="Arrow2Lend"
       style="overflow:visible;"
       inkscape:isstock="true"
       inkscape:collect="always">
      <path
         id="path2370"
         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
         transform="scale(1.1) rotate(180) translate(1,0)" />
    </marker>
    <marker
       inkscape:stockid="Arrow1Lstart"
       orient="auto"
       refY="0.0"
       refX="0.0"
       id="Arrow1Lstart"
       style="overflow:visible"
       inkscape:isstock="true">
      <path
         id="path2349"
         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
         transform="scale(0.8) translate(12.5,0)" />
    </marker>
    <marker
       inkscape:isstock="true"
       style="overflow:visible"
       id="marker2881"
       refX="0"
       refY="0"
       orient="auto"
       inkscape:stockid="Arrow1Lend">
      <path
         inkscape:connector-curvature="0"
         transform="matrix(-0.8,0,0,-0.8,-10,0)"
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
         d="M 0,0 5,-5 -12.5,0 5,5 Z"
         id="path2879" />
    </marker>
    <marker
       inkscape:stockid="Arrow2Mend"
       orient="auto"
       refY="0"
       refX="0"
       id="Arrow2Mend"
       style="overflow:visible"
       inkscape:isstock="true">
      <path
         id="path2376"
         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
         transform="scale(-0.6)"
         inkscape:connector-curvature="0" />
    </marker>
    <rect
       x="181.424"
       y="14.447854"
       width="59.731693"
       height="138.30492"
       id="rect1973" />
    <rect
       x="189.44167"
       y="1.6195705"
       width="10.42298"
       height="70.956436"
       id="rect921" />
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath1865">
      <rect
         id="rect1867"
         width="12.587744"
         height="18.216162"
         x="164.82741"
         y="85.805176"
         style="opacity:0.49;stroke-width:0.264583" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath1981">
      <rect
         style="opacity:0.49;stroke-width:0.264583"
         id="rect1983"
         width="14.431818"
         height="18.440657"
         x="218.70618"
         y="103.84495" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath1987">
      <rect
         style="opacity:0.49;stroke-width:0.264583"
         id="rect1989"
         width="13.790401"
         height="17.815268"
         x="234.34065"
         y="150.74835" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2063">
      <rect
         style="opacity:0.49;stroke-width:0.264583"
         id="rect2065"
         width="12.98864"
         height="18.617052"
         x="226.56351"
         y="132.93307" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2153">
      <rect
         y="87.232323"
         x="276.67398"
         height="18.039772"
         width="12.828283"
         id="rect2155"
         style="opacity:0.49;stroke-width:0.246057" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2157">
      <rect
         style="opacity:0.49;stroke-width:0.246057"
         id="rect2159"
         width="12.828283"
         height="18.039772"
         x="238.99091"
         y="167.00821" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2161">
      <rect
         y="197.42726"
         x="252.54079"
         height="18.039772"
         width="12.828283"
         id="rect2163"
         style="opacity:0.49;stroke-width:0.246057" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2247">
      <rect
         style="opacity:0.49;stroke-width:0.264583"
         id="rect2249"
         width="11.465286"
         height="16.307951"
         x="259.75668"
         y="181.34381" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2251">
      <rect
         style="opacity:0.49;stroke-width:0.264583"
         id="rect2253"
         width="11.465286"
         height="16.307951"
         x="246.92841"
         y="155.68724" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2255">
      <rect
         style="opacity:0.49;stroke-width:0.264583"
         id="rect2257"
         width="11.465286"
         height="16.307951"
         x="234.90189"
         y="127.62538" />
    </clipPath>
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath2259">
      <rect
         y="209.42171"
         x="271.62283"
         height="16.307951"
         width="11.465286"
         id="rect2261"
         style="opacity:0.49;stroke-width:0.264583" />
    </clipPath>
  </defs>
  <sodipodi:namedview
     inkscape:window-maximized="0"
     inkscape:window-y="147"
     inkscape:window-x="980"
     inkscape:window-height="984"
     inkscape:window-width="1660"
     showgrid="false"
     inkscape:document-rotation="0"
     inkscape:current-layer="layer1"
     inkscape:document-units="px"
     inkscape:cy="324.09656"
     inkscape:cx="468.37884"
     inkscape:zoom="1.01"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     borderopacity="1.0"
     bordercolor="#666666"
     pagecolor="#ffffff"
     id="base"
     inkscape:pagecheckerboard="true"
     showborder="true"
     borderlayer="false"
     inkscape:showpageshadow="true"
     units="px"
     fit-margin-top="0"
     fit-margin-left="0"
     fit-margin-right="0"
     fit-margin-bottom="0"
     showguides="true"
     scale-x="0.4" />
  <metadata
     id="metadata486">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     id="layer1"
     inkscape:groupmode="layer"
     inkscape:label="Layer 1"
     transform="translate(-8.2421722,-17.654924)">
    <text
       id="text764"
       y="27.663216"
       x="31.955853"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="27.663216"
         x="31.955853"
         id="tspan762"
         sodipodi:role="line">Collapse model to only variables that match search term </tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="38.246552"
         x="31.955853"
         sodipodi:role="line"
         id="tspan843" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="32.340324"
       y="52.911823"
       id="text849"><tspan
         id="tspan847"
         sodipodi:role="line"
         x="32.340324"
         y="52.911823"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">View entire model starting from root</tspan><tspan
         sodipodi:role="line"
         x="32.340324"
         y="63.495159"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan853" /></text>
    <text
       xml:space="preserve"
       id="text919"
       style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect921);fill:#000000;fill-opacity:1;stroke:none;" />
    <text
       xml:space="preserve"
       id="text1971"
       style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1973);fill:#000000;fill-opacity:1;stroke:none;" />
    <image
       id="image2057"
       xlink:href=" YGASSCwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwiDKwM6gwMCamFxc4BgQ4ANUwgCjUcG3awyMIPqy Lsis1CkdCuJTD38vs4qKE165Lh1TPQrgSkktTgbSf4A4JbmgqISBgTEByFYuLykAsVuAbJEioKOA 7BkgdjqEvQbEToKwD4DVhAQ5A9lXgGyB5IzEFCD7CZCtk4Qkno7EhtoLdoOPu4KHS5CCiTcBx5IK SlIrSkC0c35BZVFmekaJgiMohBQ885L1dBSMDIwMGBhA4Q1R/VkMHI6MYqcQYpXXGRgsAoGMGIRY yE0Ghl0BDAzcsxFiGmoMDLzAcDtuWpBYlAh3AOM3luI0YyMIm6eIgYH1x///n2UZGNh3MTD8Lfr/ //fc////LmFgYAaaeaAQADtrXUO2vphQAAAACXBIWXMAABYlAAAWJQFJUiTwAAABnWlUWHRYTUw6 Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4 bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cu dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9u IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29t L2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4yMjA8L2V4aWY6UGl4 ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTAyPC9leGlmOlBp eGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94 OnhtcG1ldGE+CmH5RkAAAAAcaURPVAAAAAIAAAAAAAAAMwAAACgAAAAzAAAAMwAACe42KA1hAAAJ uklEQVR4AexdC1RU1xXdDAwMOKAgivgBf/EHaIiK36hR8YemfpJYTawxaVITm9qmyUo0XXY1Nm1q 0tXYFZO0sbaadMVWbWzwFyoxNVKjYiWKYLQoKvhBRfGDKDL0nte+ybzhzvDeMA8Y1zlr4Z177r1n 3tvv7vs597wxaP7aX9SChRFgBHQjEAQLgmqDxV8IgmtDYam1ir8w8dmGEEe4knoyFsSE8wQN6xkB XxCwCNLZYHXYRWoXaQuFjKolJpyKBKeMgAkI0AxorYlEqKOVSKPAhDMBZDbJCMgQsNbYmXAyYFjH CJiFAM9wZiHLdhkBCQJMOAkorGIEzEKACWcWsmyXEZAgwISTgMIqRsAsBJhwZiHLdhkBCQJMOAko rGIEzEKACWcWsmyXEZAgwISTgMIqRsAsBJhwZiHLdhkBCQJMOAkorGIEzEKACWcWsmyXEZAgwIST gMIqRsAsBJhwZiHLdhkBCQJMOAkorGIEzEKACWcWsmyXEZAgwISTgMIqRsAsBJhwZiHLdhkBCQJM OAkorGIEzEKACWcWsmyXEZAgwISTgMIqRsAsBJhwZiHLdhkBCQJMOAkorGIEzEKACWcWsmyXEZAg EBCE69+pN+Jbxkouv67qy+JDuHj9St2Cu1zDGAXGA/aZcLH2Vugc0x5RthY4f+0SCs+dgKPWnP8X 5Kmh03Bfp166EF3++Uc4cr5YV12zKzFGZiMcePYNE84aHIJvpYzE6J5pCHK53wvXL2PFznUK+VzU fvkYaIRjjPzy2O9KI4YJN2/wg0hLTJKCQaT71T9W48btm9JyX5WBRjjGyNcnbbxdq/BITEwapvRJ W0ioRwOnLp/D9q/3Yt/Jwx7rNEaBIcIlxXfF90fM9HpddGPHyk55rWO0MKV9d7SNjNHVrKmXlIyR rsekVLIEWTCkSwq6tO7w/61JOXKO5+Hc1Uu6jcwaMAEjuqXqqk9bnlcyV+DKzWu66gdbLBjcOQU9 2ibAFhKG0ooy7D9VKNILutrLKhki3MOpYzG6x0CZnWaja2rCMUb6ukIbezS+O3QqEqLbaRrUClKs 3rsJe4rzNXpPmbdm/BhhXmY293Yb8j4TM90ed3WdfGiwFS+MmYNO0XGasjuOGmQe2omsI19q9Hoz hgj37P0Pg2ab5ixNTTjGqP7eQTPbS+lz65BNbUmd+tfZH6K4/Iyq8pi+O3ORxzJZwebDu7Ap/wtZ kUb35JCpGJDQW6NzzfwuZwPySo66qnR9NkS4GfeOwVjhLGnO0tSEY4zq7x3DuvbDYwMnea14teoG Cs4dl9ahjv5V6f86e0MIN3fQZKl9e2g4kuuZWC5XXsPizLel7b0pDRGud7su+MHIb3uzh+MXS4Rb /qTXOkYL6UigXVRrXc2amnCMUf2PichGpPNVXGephhDOaFv36130ydu694NqW0OEo0bfScsQG92+ antNSpvdZdvX4GZ1lUbf0EygeSkZI+9PfP7wh9Cvwz3eK3kpbS6Ee+3TVSi5ct7LldYtMky4EEsw MpKGY1zvIbAEfXMSR2R754t1oKMBf0ugEY4x8t4DHkwZgYl9hnmv5KW0ORDOUevAwvVvgvabRsQw 4VTjLcPtSIyOR6QtQhx2l6PowmmYE2cCZT3dVni1VJmcPBzhVpuaVTxGFTevK/kDJV/jcuVVZ1lT fmCM5Oh3aNkGL4+bBxqYPMmOY7nIFudm7jLqnv6oqr4NIh2J0WWhK1lfzZiPD/ZuQXllheZromx2 PDdypuhjYRq9a2bfqQKs2v13V5Wuzz4TTpd1kyq9NmUBYiKinNZ/vm1lg85GnIaa+ENcZGukduyB 9qJDElmra2pQUXVNDGalOHjmKK7f0h9Q0NwxGtdrMKb1e0CK+NGyk1j++VoRKuhwlkeE2jBnYAbu Ffi4kqYhhKO2lbersGbvZqcTRv3CpPhuWCC88kEuqzi1jAZ0Wk76EuDBhFNRbMKUyDW7/wT09bKv oc63rWA3thTsQo3jm47o6bKbO+Houok8j6SOQ3REpHIbdAaXe7oQf/13lmZwiW3RCj96YDZiWrRU 6lHEyIa8bOXzIjFTup/lKQUe/lkhtj35Z/4Dm5i9fjP9eWctVxKrygEJfTCt7yjn99Iz2H/6CP6y P8snspFdJpyKbhOlgzoni06XDhrBb92pRvGlMzhZftZ5BhUrltLJIsKne5sEZc9ccqUMq/dkis16 mdcrDgTCqTdA4VkUBH9BvOXh7nCzh0XgRXEA7RppVCQ84W9mf6A0HyjCDB8fNEXjT1DtuqdnKy5i 6acrQcTuFdcZC0fN0lRZd2A7Pju6T6MjP0VrQXibNRTU3uieTWNMZJhw7og0Yn66WFKli6UVySEx 6v45dyvUvajrZUSL5fOi9HnKfpn0NMP99p9rQUsvTxJIhPN0D2EhVjGzPYrEmHhNFYry+PirHU4d EZZmIyKFJ6FBLP9skUI2qkORLs+PfhTUVhXyQazavRG5InzLLGHCmYVsPXa7t+kkHvhjogM48OG+ rdh94qC0Bb15QCFG6rKJ4gFp1C0X+4ilYu9aVX1L2u5uINyctEkY2kV7XudONunN61TSrElLVVfS 0Qz26tb3TfG202Ux4XQ+HH9Wo5H7lfFPKqPs1oIcfCJi8zzJE+LtDFo2kdAI/HsRUpTecxC6xnZU SEobfpkEOuFogHk5/XGN08KfZFMxk5HuYOkxvLtrvVrFrykTzq9w6jNG7xNO6DNU8ay+nvVHj/sC Wm7SslOVzPyd2HI4B/FRsVg8/gnFrf6G2MtQdI+7BDrhaFbvJgYVVXYV5SlLbjXvz5RIt1g4X1yD oGnJTi9V+1uYcP5GVIe9pZOfAXneaBSl0VQm9JrPgvsfcY7wdL74fs7fnGeds/qPx4ju9+HjgzuQ VVg3cj2QCUcB8hQErkp1zR38ZNM7oPhKs+QhESc8xiVOmF4z+6UYDP0tTDh/I1qPPRpNfzbpe0qt FzcuF+7vyjot4kQdiqZXD/dLhUfyjew1ihdTrZyWmIx5g6cIN3UhVv5ro6p2poFMOLovuj9VdhYd wEe529SsKSkdTSzNeBb0DpwqSza/5/e9HBNORbeR0p5xifjhqNm4dKNCGbXdv5bOh14aO9cZrE2H q69n/QkXb2h/GIl+VGnJhKeUDkEdw10ClXAUfbJs6kJnlAc5iX665b1G+WEo9xhY8oT6+t6b+/NQ 80w4FYlGSlM79sTTw6Yr+wPaJ7gKRTU8IwJ71XcO6aCVIi5k7n9yvLw14wXliOC59cuc7m7VXqAS zv2N+VwRQvUHH0KoVByMpPRGypKJTzt/q+eEOBNdtn21ERP11v0vAAAA//+FKiRIAAAGbklEQVTt m3lsFUUcx7/vagulBUq5oaRSagqCRWqQS6QptEQJKMGAiBcEjaIRogaCZ9B6BOEPIiYqURGiARUV ubVNMBw1QGwgQKQCttyFtpSWFtr3nvNb8x50u2/7KKXzhvlN0rydY/c3v89vvzu7M1PHc9/l+qFY em/CC0hoGx/s9bubv8DJi6XBfCQf9OvcG/MyH8f5qgq8seHTBl2dOHA0cvoPD5at2bcN+Uf2BPPX HyR36onXsp4w/Cb/zUllRmZfbqe8gwXXuuHs2DYOuRPmgJ5yL3+/GFe9dUYHhvROw6zhk4Kd2Xms EN/8uTGYNx+MSc3Ao4PHYvfx/fi64FdzNVhwjZBERAELTkIYFmY/g14duhpCIcHQ8atZMxDl8hi9 OXrhJJbmrUa9zxuyd8+OmIz0XqkINQqqJLikjt0woHtfuJxOS3+9Ph8OnC5CSflZy/qbLYx2R4Ee eAmx196azNcsq67E3pKDuFL//wPSXB9ungUXLqkWbDc65R5MHZKNssuVWPz7SrySOUMEu71hoaLm Et7f+iUqa6tDWkzrloyXRk8F3YiLxOvk2UsXGrVVRXDTBIf7BY9w0vaiffh275ZwmobdpktcAhaM fQoxnugmz6mtu4JcEZvSqvIm24ZqwIILReYWljscDuM7LiWxF6qv1iA2qo1hrc5bj4/zVuHfstMh rdON8WbOLHQU37C/7N+OTQd3WLZVQXDk9wcTX4Tb6bL0wVxII/78n5cZzMx1zc1PTs9E1p1Dwz59 2+EC/FiYF3Z7c0MWnJlIK+Xpyfp69kx4XO6gxa8K1qPg+IFg3nyQGNsBTw59CCli4oVE+dFvK+Hz +8zNjLwKgkvtkoS5Y6Zb9j9U4dL81fj7XHGo6hsun5c5Hf06J4V93pHSYiwRr/vNTSy45pJrgfNG 3pGOaRk5cIoRr1y8Xn6+cx2OXTjV6MpOhxOj+qbj4bszEe324FLtZSzJX4UzlY1fJQMns+ACJOx/ WXD2fIzaXLEsQK9UgaTSskCgz4HfPgndjVGre3yiUUQTA8XlZ8SyQTniYmJB9TSpEBgJ95UcFt8x m1F1pSZwCctfFRjxCGcZusgppG8fWqvKThvWoFN0E9LrGH0DqZjoG+bBASNBU/00Y2aVaAT84a88 MVN2yKo6WKYSIxZcMGyRd0BP+NkjHsFdYvrYKhWdP4Hl29eipq7WqlqJMvIxrWsyerRPRHybdqj3 enGxtgr/lJ4Q32ynjLU7O0dUY8SCs4um5LrM1HsxZXCWbS+2Ht6NdYX5tm1u50rVGLHgIvhupG1M tJ3JLtG61sL1n9g1ua3rVGPEgovg25G2Q9G2KLtEU+Rz1nzY5KuX3TVUrlONEU0GLRj39A0hp00B NKnUUun5UVMwsEdK2Jfbf6oIy/9YG3Z7c0NllgXmjnkMqV36mPvfIE87Lt7e+FmDMp0yKjJ6a/xs dIvvFFaYaBnknU0tG9+MpDTMHHZtD2tTHVmx6yfsKbafuLK7hjKCo5nJSYMesPPF2FlPewt1TSoy os+EnP7DxGRYirEeaRU7n99v7KXcfHCXWKc8adWk2WU0Qzwu7T7Qmuj1S03mC9Is8Y6jhdhyaJft Hlfzeea8MoKjja3zxZ432uhrlcqqL2LRlhWg/W66JmYU+ZFXRnCEMl4sBE/PGI9BPfs1IEvbbVYW bMD56ooG5TpmmFFkR10pwQVQ0sc2/dGWqJKKczguXjOU+y/agDO36JcZ3SKwN3lZJQV3kz7z6UxA GgEWnDT0bFhHAiw4HaPOPksjwIKThp4N60iABadj1NlnaQRYcNLQs2EdCbDgdIw6+yyNAAtOGno2 rCMBFpyOUWefpRFgwUlDz4Z1JMCC0zHq7LM0Aiw4aejZsI4EWHA6Rp19lkaABScNPRvWkQALTseo s8/SCLDgpKFnwzoSYMHpGHX2WRoBFpw09GxYRwIsOB2jzj5LI8CCk4aeDetIgAWnY9TZZ2kEWHDS 0LNhHQmw4HSMOvssjQALThp6NqwjARacjlFnn6URYMFJQ8+GdSTAgtMx6uyzNAIsOGno2bCOBFhw OkadfZZGgAUnDT0b1o2Ax9cOLDjdos7+tioBlz8KHm8conwdxG88C65V6bMxDQg44fbFgEYzt/jz +GLh9EcH/eYRLoiCD5hAeAQccMLhd4k/N2gEc/o9hqhc/hghsjaiLCbkhf4DuBaYvUHsIyAAAAAA SUVORK5CYII= "
       preserveAspectRatio="none"
       height="17.991667"
       width="38.805557"
       x="226.96439"
       y="166.60732"
       clip-path="url(#clipPath2157)"
       transform="translate(-24.882557,-47.713458)" />
    <image
       y="197.47537"
       x="226.56351"
       width="38.805557"
       height="17.991667"
       preserveAspectRatio="none"
       xlink:href=" YGASSCwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwiDKwM6gwMCamFxc4BgQ4ANUwgCjUcG3awyMIPqy Lsis1CkdCuJTD38vs4qKE165Lh1TPQrgSkktTgbSf4A4JbmgqISBgTEByFYuLykAsVuAbJEioKOA 7BkgdjqEvQbEToKwD4DVhAQ5A9lXgGyB5IzEFCD7CZCtk4Qkno7EhtoLdoOPu4KHS5CCiTcBx5IK SlIrSkC0c35BZVFmekaJgiMohBQ885L1dBSMDIwMGBhA4Q1R/VkMHI6MYqcQYpXXGRgsAoGMGIRY yE0Ghl0BDAzcsxFiGmoMDLzAcDtuWpBYlAh3AOM3luI0YyMIm6eIgYH1x///n2UZGNh3MTD8Lfr/ //fc////LmFgYAaaeaAQADtrXUO2vphQAAAACXBIWXMAABYlAAAWJQFJUiTwAAABnWlUWHRYTUw6 Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4 bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cu dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9u IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29t L2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4yMjA8L2V4aWY6UGl4 ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTAyPC9leGlmOlBp eGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94 OnhtcG1ldGE+CmH5RkAAAAAcaURPVAAAAAIAAAAAAAAAMwAAACgAAAAzAAAAMwAACe42KA1hAAAJ uklEQVR4AexdC1RU1xXdDAwMOKAgivgBf/EHaIiK36hR8YemfpJYTawxaVITm9qmyUo0XXY1Nm1q 0tXYFZO0sbaadMVWbWzwFyoxNVKjYiWKYLQoKvhBRfGDKDL0nte+ybzhzvDeMA8Y1zlr4Z177r1n 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 SUVORK5CYII= "
       id="image2059"
       clip-path="url(#clipPath2161)"
       transform="translate(-38.432437,-59.210828)" />
    <image
       y="127.62538"
       x="234.90189"
       width="49.388889"
       height="16.580555"
       preserveAspectRatio="none"
       xlink:href=" YGASSCwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwiDKwM6gwMCamFxc4BgQ4ANUwgCjUcG3awyMIPqy Lsis1CkdCuJTD38vs4qKE165Lh1TPQrgSkktTgbSf4A4JbmgqISBgTEByFYuLykAsVuAbJEioKOA 7BkgdjqEvQbEToKwD4DVhAQ5A9lXgGyB5IzEFCD7CZCtk4Qkno7EhtoLdoOPu4KHS5CCiTcBx5IK SlIrSkC0c35BZVFmekaJgiMohBQ885L1dBSMDIwMGBhA4Q1R/VkMHI6MYqcQYpXXGRgsAoGMGIRY yE0Ghl0BDAzcsxFiGmoMDLzAcDtuWpBYlAh3AOM3luI0YyMIm6eIgYH1x///n2UZGNh3MTD8Lfr/ //fc////LmFgYAaaeaAQADtrXUO2vphQAAAACXBIWXMAABYlAAAWJQFJUiTwAAABnGlUWHRYTUw6 Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4 bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cu dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9u IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29t L2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4yODA8L2V4aWY6UGl4 ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+OTQ8L2V4aWY6UGl4 ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6 eG1wbWV0YT4KefllMAAAABxpRE9UAAAAAgAAAAAAAAAvAAAAKAAAAC8AAAAvAAAGW2cWbGcAAAYn SURBVHgB7JzPilRHFMbrOoOKEzIjCf4LBAnGhRCYbIIEFy5diY+QpW/ha7iLjyBZuRSSRcgmA4Es VIIISggBFQRnxta2v84cqZTn1q1zb92equ6voLnd1bdOnfOrr7653beZ5tbPP04dGwmQAAloBJrG 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 Jiv+B8Agvd5HrQZBAAAAAElFTkSuQmCC "
       id="image2225"
       clip-path="url(#clipPath2255)"
       transform="translate(-20.073258,-89.40194)" />
    <image
       id="image2229"
       xlink:href=" YGASSCwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwiDKwM6gwMCamFxc4BgQ4ANUwgCjUcG3awyMIPqy Lsis1CkdCuJTD38vs4qKE165Lh1TPQrgSkktTgbSf4A4JbmgqISBgTEByFYuLykAsVuAbJEioKOA 7BkgdjqEvQbEToKwD4DVhAQ5A9lXgGyB5IzEFCD7CZCtk4Qkno7EhtoLdoOPu4KHS5CCiTcBx5IK SlIrSkC0c35BZVFmekaJgiMohBQ885L1dBSMDIwMGBhA4Q1R/VkMHI6MYqcQYpXXGRgsAoGMGIRY yE0Ghl0BDAzcsxFiGmoMDLzAcDtuWpBYlAh3AOM3luI0YyMIm6eIgYH1x///n2UZGNh3MTD8Lfr/ //fc////LmFgYAaaeaAQADtrXUO2vphQAAAACXBIWXMAABYlAAAWJQFJUiTwAAABnGlUWHRYTUw6 Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4 bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cu dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9u IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29t L2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4yODA8L2V4aWY6UGl4 ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+OTQ8L2V4aWY6UGl4 ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6 eG1wbWV0YT4KefllMAAAABxpRE9UAAAAAgAAAAAAAAAvAAAAKAAAAC8AAAAvAAAGW2cWbGcAAAYn SURBVHgB7JzPilRHFMbrOoOKEzIjCf4LBAnGhRCYbIIEFy5diY+QpW/ha7iLjyBZuRSSRcgmA4Es VIIISggBFQRnxta2v84cqZTn1q1zb92equ6voLnd1bdOnfOrr7653beZ5tbPP04dGwmQAAloBJrG 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 Jiv+B8Agvd5HrQZBAAAAAElFTkSuQmCC "
       preserveAspectRatio="none"
       height="16.580555"
       width="49.388889"
       x="234.50101"
       y="155.28636"
       clip-path="url(#clipPath2251)"
       transform="translate(-32.099778,-99.65923)" />
    <image
       y="181.08723"
       x="234.10013"
       width="49.388889"
       height="16.580555"
       preserveAspectRatio="none"
       xlink:href=" YGASSCwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwiDKwM6gwMCamFxc4BgQ4ANUwgCjUcG3awyMIPqy Lsis1CkdCuJTD38vs4qKE165Lh1TPQrgSkktTgbSf4A4JbmgqISBgTEByFYuLykAsVuAbJEioKOA 7BkgdjqEvQbEToKwD4DVhAQ5A9lXgGyB5IzEFCD7CZCtk4Qkno7EhtoLdoOPu4KHS5CCiTcBx5IK SlIrSkC0c35BZVFmekaJgiMohBQ885L1dBSMDIwMGBhA4Q1R/VkMHI6MYqcQYpXXGRgsAoGMGIRY yE0Ghl0BDAzcsxFiGmoMDLzAcDtuWpBYlAh3AOM3luI0YyMIm6eIgYH1x///n2UZGNh3MTD8Lfr/ //fc////LmFgYAaaeaAQADtrXUO2vphQAAAACXBIWXMAABYlAAAWJQFJUiTwAAABnGlUWHRYTUw6 Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4 bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cu dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9u IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29t L2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4yODA8L2V4aWY6UGl4 ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+OTQ8L2V4aWY6UGl4 ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6 eG1wbWV0YT4KefllMAAAABxpRE9UAAAAAgAAAAAAAAAvAAAAKAAAAC8AAAAvAAAGW2cWbGcAAAYn SURBVHgB7JzPilRHFMbrOoOKEzIjCf4LBAnGhRCYbIIEFy5diY+QpW/ha7iLjyBZuRSSRcgmA4Es VIIISggBFQRnxta2v84cqZTn1q1zb92equ6voLnd1bdOnfOrr7653beZ5tbPP04dGwmQAAloBJrG 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 Jiv+B8Agvd5HrQZBAAAAAElFTkSuQmCC "
       id="image2231"
       clip-path="url(#clipPath2247)"
       transform="translate(-44.928055,-107.63951)" />
    <image
       id="image2233"
       xlink:href=" YGASSCwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwiDKwM6gwMCamFxc4BgQ4ANUwgCjUcG3awyMIPqy Lsis1CkdCuJTD38vs4qKE165Lh1TPQrgSkktTgbSf4A4JbmgqISBgTEByFYuLykAsVuAbJEioKOA 7BkgdjqEvQbEToKwD4DVhAQ5A9lXgGyB5IzEFCD7CZCtk4Qkno7EhtoLdoOPu4KHS5CCiTcBx5IK SlIrSkC0c35BZVFmekaJgiMohBQ885L1dBSMDIwMGBhA4Q1R/VkMHI6MYqcQYpXXGRgsAoGMGIRY yE0Ghl0BDAzcsxFiGmoMDLzAcDtuWpBYlAh3AOM3luI0YyMIm6eIgYH1x///n2UZGNh3MTD8Lfr/ //fc////LmFgYAaaeaAQADtrXUO2vphQAAAACXBIWXMAABYlAAAWJQFJUiTwAAABnGlUWHRYTUw6 Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4 bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cu dzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9u IHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29t L2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4yODA8L2V4aWY6UGl4 ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+OTQ8L2V4aWY6UGl4 ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6 eG1wbWV0YT4KefllMAAAABxpRE9UAAAAAgAAAAAAAAAvAAAAKAAAAC8AAAAvAAAGW2cWbGcAAAYn SURBVHgB7JzPilRHFMbrOoOKEzIjCf4LBAnGhRCYbIIEFy5diY+QpW/ha7iLjyBZuRSSRcgmA4Es VIIISggBFQRnxta2v84cqZTn1q1zb92equ6voLnd1bdOnfOrr7653beZ5tbPP04dGwmQAAloBJrG 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 Jiv+B8Agvd5HrQZBAAAAAElFTkSuQmCC "
       preserveAspectRatio="none"
       height="16.580555"
       width="49.388889"
       x="233.69923"
       y="209.14911"
       clip-path="url(#clipPath2259)"
       transform="translate(-56.794205,-117.91283)" />
    <text
       id="text2267"
       y="48.904755"
       x="228.07339"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="48.904755"
         x="228.07339"
         sodipodi:role="line"
         id="tspan2263">Collapse variables in current view</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="59.488091"
         x="228.07339"
         sodipodi:role="line"
         id="tspan2269" /><tspan
         id="tspan2265"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="70.071434"
         x="228.07339"
         sodipodi:role="line" /></text>
    <text
       id="text2275"
       y="66.541878"
       x="31.749147"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="66.541878"
         x="31.749147"
         sodipodi:role="line"
         id="tspan2271">Move back in view history</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="77.125214"
         x="31.749147"
         sodipodi:role="line"
         id="tspan2343" /><tspan
         id="tspan2273"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="87.708549"
         x="31.749147"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none"
       x="31.749147"
       y="78.571922"
       id="text2281"><tspan
         id="tspan2277"
         sodipodi:role="line"
         x="31.749147"
         y="78.571922"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none">Move forward in view history</tspan><tspan
         sodipodi:role="line"
         x="31.749147"
         y="89.155258"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none"
         id="tspan2345" /><tspan
         sodipodi:role="line"
         x="31.749147"
         y="99.738594"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none"
         id="tspan2279" /></text>
    <text
       id="text2287"
       y="96.60817"
       x="31.955853"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="96.60817"
         x="31.955853"
         sodipodi:role="line"
         id="tspan2283">Control variable collapsing</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="107.19151"
         x="31.955853"
         sodipodi:role="line"
         id="tspan2795" /><tspan
         id="tspan2285"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="117.77484"
         x="31.955853"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="31.997194"
       y="115.84883"
       id="text2293"><tspan
         id="tspan2289"
         sodipodi:role="line"
         x="31.997194"
         y="115.84883"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Set connections visibility</tspan><tspan
         sodipodi:role="line"
         x="31.997194"
         y="126.43217"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2797" /><tspan
         sodipodi:role="line"
         x="31.997194"
         y="137.0155"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2291" /></text>
    <text
       id="text2299"
       y="132.68596"
       x="31.997194"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="132.68596"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2295">Show non-linear / Show linear solvers</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="143.2693"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2799" /><tspan
         id="tspan2297"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="153.85263"
         x="31.997194"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="31.997194"
       y="149.12749"
       id="text2305"><tspan
         id="tspan2301"
         sodipodi:role="line"
         x="31.997194"
         y="149.12749"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Show legend / Hide legend</tspan><tspan
         sodipodi:role="line"
         x="31.997194"
         y="159.71083"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2801" /><tspan
         sodipodi:role="line"
         x="31.997194"
         y="170.29416"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2303" /></text>
    <text
       id="text2311"
       y="181.59908"
       x="31.997194"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="181.59908"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2307">Set collapse depth</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="192.18242"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2805" /><tspan
         id="tspan2309"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="202.76575"
         x="31.997194"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="31.997194"
       y="166.35843"
       id="text2317"><tspan
         id="tspan2313"
         sodipodi:role="line"
         x="31.997194"
         y="166.35843"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Set text height</tspan><tspan
         sodipodi:role="line"
         x="31.997194"
         y="176.94177"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2803" /><tspan
         sodipodi:role="line"
         x="31.997194"
         y="187.5251"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2315" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="31.997194"
       y="196.82736"
       id="text2323"><tspan
         id="tspan2319"
         sodipodi:role="line"
         x="31.997194"
         y="196.82736"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Set model height</tspan><tspan
         sodipodi:role="line"
         x="31.997194"
         y="207.41071"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2321" /></text>
    <text
       id="text2329"
       y="213.26891"
       x="31.997194"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="213.26891"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2325">Save to SVG</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="223.85225"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2807" /><tspan
         id="tspan2327"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="234.43558"
         x="31.997194"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="31.997194"
       y="231.36636"
       id="text2335"><tspan
         id="tspan2331"
         sodipodi:role="line"
         x="31.997194"
         y="231.36636"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Show connection matrix information / Hide connection matrix information</tspan><tspan
         sodipodi:role="line"
         x="31.997194"
         y="241.94971"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2809" /><tspan
         sodipodi:role="line"
         x="31.997194"
         y="252.53304"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2333" /></text>
    <text
       id="text2341"
       y="250.70869"
       x="31.997194"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="250.70869"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2337">Show this N2 Help page</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="261.29205"
         x="31.997194"
         sodipodi:role="line"
         id="tspan2811" /><tspan
         id="tspan2339"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="271.8754"
         x="31.997194"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="227.82535"
       y="66.044159"
       id="text2819"><tspan
         id="tspan2813"
         sodipodi:role="line"
         x="227.82535"
         y="66.044159"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Expand variables in current view</tspan><tspan
         sodipodi:role="line"
         x="227.82535"
         y="76.627495"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2853" /><tspan
         id="tspan2815"
         sodipodi:role="line"
         x="227.82535"
         y="87.210831"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583" /><tspan
         sodipodi:role="line"
         x="227.82535"
         y="97.794174"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2817" /></text>
    <text
       id="text2827"
       y="83.64415"
       x="228.07339"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="83.64415"
         x="228.07339"
         sodipodi:role="line"
         id="tspan2821">Collapse all variables in entire model</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="94.227486"
         x="228.07339"
         sodipodi:role="line"
         id="tspan2855" /><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="104.81082"
         x="228.07339"
         sodipodi:role="line"
         id="tspan2823" /><tspan
         id="tspan2825"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="115.39417"
         x="228.07339"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="227.82535"
       y="101.43807"
       id="text2835"><tspan
         id="tspan2829"
         sodipodi:role="line"
         x="227.82535"
         y="101.43807"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Expand all variables in entire model</tspan><tspan
         sodipodi:role="line"
         x="227.82535"
         y="112.02141"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2857" /><tspan
         id="tspan2831"
         sodipodi:role="line"
         x="227.82535"
         y="122.60474"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583" /><tspan
         sodipodi:role="line"
         x="227.82535"
         y="133.18808"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2833" /></text>
    <text
       id="text2843"
       y="131.21997"
       x="229.02104"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       xml:space="preserve"><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="131.21997"
         x="229.02104"
         sodipodi:role="line"
         id="tspan2837">Remove all connection arrows</tspan><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="141.80331"
         x="229.02104"
         sodipodi:role="line"
         id="tspan2861" /><tspan
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="152.38664"
         x="229.02104"
         sodipodi:role="line"
         id="tspan2839" /><tspan
         id="tspan2841"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         y="162.96999"
         x="229.02104"
         sodipodi:role="line" /></text>
    <text
       xml:space="preserve"
       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;line-height:1.25;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
       x="229.3187"
       y="150.63814"
       id="text2851"><tspan
         id="tspan2845"
         sodipodi:role="line"
         x="229.3187"
         y="150.63814"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583">Show all connections in view</tspan><tspan
         sodipodi:role="line"
         x="229.3187"
         y="161.22148"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2863" /><tspan
         id="tspan2847"
         sodipodi:role="line"
         x="229.3187"
         y="171.80481"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583" /><tspan
         sodipodi:role="line"
         x="229.3187"
         y="182.38815"
         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.46667px;font-family:Arial;-inkscape-font-specification:'Arial Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
         id="tspan2849" /></text>
    <path
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.40256;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-mid:url(#Arrow2Lend);marker-end:url(#marker3033)"
       d="m 139.50457,92.612045 65.46564,-18.59487"
       id="path2877"
       inkscape:connector-type="polyline"
       inkscape:connector-curvature="0" />
    <path
       inkscape:connector-curvature="0"
       inkscape:connector-type="polyline"
       id="path3353"
       d="m 139.55212,113.53618 68.0482,11.13224"
       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.10641;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-mid:url(#marker3357);marker-end:url(#marker3367)" />
    <image
       id="image162"
       xlink:href="
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
"
       style="image-rendering:optimizeSpeed"
       preserveAspectRatio="none"
       height="244.32474"
       width="21.460957"
       x="8.56005"
       y="17.804443" />
  </g>
</svg>
</div>

<div class="modal-footer">OpenMDAO Model Hierarchy and N2 diagram</div>
</div>
</div>


        <!-- Toolbar -->
        <div id="toolbarLoc">
            <div class="searchbar-container" id="searchbar-container">
                <button class="search-button" id="searchButtonId" title="Search">
                    <i class="fas icon-search"></i>
                </button>
                <div id='searchbar-and-label' class='searchbar-hidden'>
                    <label id='searchCountId' for='awesompleteId'>0 matches</label>
                    <input type="text" tabindex="-1" size="80" placeholder="Search" id="awesompleteId"
                        class="searchbar" />
                </div>
            </div>
            <div class="toolbar" id="true-toolbar">
                <div class="toolbar-group group-1">
                    <i class="fas icon-home2" id="reset-graph"></i>
                    <i class="fas icon-backward" id="undo-graph"></i>
                    <i class="fas icon-forward" id="redo-graph"></i>
                </div>
                <div class="toolbar-group group-2">
                    <div class="expandable">
                        <i class="fas icon-shrink2" id="collapse-element"></i>
                        <i class="fas icon-caret-right caret"></i>
                        <div class="toolbar-group-expandable" id="collapse-expandable">
                            <i class="fas icon-shrink2" id="collapse-element-2"></i>
                            <i class="fas icon-enlarge2" id="expand-element"></i>
                            <i class="fas icon-shrink" id="collapse-all"></i>
                            <i class="fas icon-enlarge" id="expand-all"></i>
                        </div>
                    </div>
                </div>
                <div class="toolbar-group group-3">
                    <div class="expandable">
                        <i class="fas icon-hide-connections" id="hide-connections"></i>
                        <i class="fas icon-caret-right caret"></i>
                        <div class="toolbar-group-expandable" id="connections-expandable">
                            <i class="fas icon-hide-connections" id="hide-connections-2"></i>
                            <i class="fas icon-bezier-curve" id="show-all-connections"></i>
                        </div>
                    </div>
                    <i class="fas icon-linear-solver solver-button" id="linear-solver-button"></i>
                    <i class="fas icon-key" id="legend-button"></i>
                </div>
                <div class="toolbar-group group-4">
                    <div class="expandable">
                        <i class="fas icon-text-height" id="text-slider-button"></i>
                        <i class="fas icon-caret-right caret"></i>
                        <div class="toolbar-group-expandable" id="text-width-expandable">
                            <input type="range" min="8" max="24" value="11" class="slider" id="text-slider" />
                            <p id="font-size-indicator">11 px</p>
                        </div>
                    </div>
                    <div class="expandable">
                        <i class="fas icon-collapse-depth" id="depth-slider-button"></i>
                        <i class="fas icon-caret-right caret"></i>
                        <div class="toolbar-group-expandable" id="model-depth-expandable">
                            <input type="range" min="0" max="10" value="0" class="slider" id="depth-slider" />
                        </div>
                    </div>
                    <div class="expandable">
                        <i class="fas icon-model-height" id="model-slider-button"></i>
                        <i class="fas icon-caret-right caret"></i>
                        <div class="toolbar-group-expandable" id="model-height-expandable">
                            <input type="range" class="slider" id="model-slider" list="model-slider-data" min='50'
                                max='200' value='95' />
                            <datalist id="model-slider-data">
                                <option value='50'></option>
                                <option value='75'></option>
                                <option value='95'></option>
                                <option value='100'></option>
                                <option value='125'></option>
                                <option value='150'></option>
                                <option value='175'></option>
                                <option value='200'></option>
                            </datalist>
                            <p id='model-slider-label'>95%</p>
                            <button id='model-slider-fit'>Fit</button>
                        </div>
                    </div>
                    <i class="fas icon-save" id="save-button"></i>
                </div>
                <div class="toolbar-group group-5">
                    <i class="fas icon-info-circle" id="info-button"></i>
                    <i class="fas icon-question-circle" id="question-button"></i>
                </div>
            </div>
        </div>

        <!-- Hide toolbar button -->
        <div class="toolbar-hide-container" id="hide-toolbar">
            <i class="fas icon-chevron-left hide-toolbar-button"></i>
        </div>

        <div id="d3_content_div">
            <!-- 2D Matrix Showing All Inputs/Outputs and Functions -->
            <div id="svgDiv">
                <div class="no-show" id="waiting-container">
                    <img id="waiting-icon" src="" alt="Processing..." />
                </div>
                <svg id="svgId">
                    <style title='svgStyle'></style>
                    <defs>
                        <marker id="arrow" viewBox="0 -5 10 10" refX="5" refY="0" markerWidth="1" markerHeight="1"
                            orient="auto">
                            <path d="M0,-5L10,0L0,5L0,-5" class="arrowHead"></path>
                        </marker>
                        <clipPath id="partitionTreeClip">
                            <rect id="tree-clip-rect" x="0" y="0" width="1200" height="600" />
                        </clipPath>
                        <clipPath id="n2MatrixClip">
                            <rect id="matrix-clip-rect" x="-1" y="-1" width="602" height="602" />
                        </clipPath>
                        <clipPath id="solverTreeClip">
                            <rect id="solver-clip-rect" x="0" y="0" width="1200" height="600" />
                        </clipPath>
                        <g id='matrix-connector-arrow' width='10' height='10'>
                            <path d='M0,3 h2 q5,0 5,5 h1 l-3,2 l-3,-2 h1 q0,-1 -1,-1 h-2 z'></path>
                        </g>
                        <g id='matrix-connector-square' width='10' height='10'>
                            <rect x='2' y='2' width='6' height='6'></rect>
                        </g>
                    </defs>
                    <g id='tree' clip-path='url(#partitionTreeClip)'></g>
                    <g id='highlight-bar'></g>
                    <g id='solver_tree' clip-path='url(#solverTreeClip)'></g>
                    <g id='n2outer'>
                        <g id='n2inner'>
                            <rect id='backgroundRect' class='background'></rect>
                            <g id='n2background' clip-path='url(#n2MatrixClip)'></g>
                            <g id='n2gridlines' clip-path='url(#n2MatrixClip)'></g>
                            <g id='n2elements' clip-path='url(#n2MatrixClip)'></g>
                            <g id='n2componentBoxes' clip-path='url(#n2MatrixClip)'></g>
                            <g id='n2arrows'></g>
                        </g>
                        <g id='n2top' class='offgridLabel'></g>
                        <g id='n2left' class='offgridLabel'></g>
                        <g id='n2right' class='offgridLabel'></g>
                        <g id='n2bottom' class='offgridLabel'></g>
                    </g>
                    <g id='text-width-renderer' class='partition_group'>
                        <text x='-200'></text>
                    </g>
                </svg>
                <div id='n2-resizer-box' class='inactive-resizer-box'>
                    <p id='n2-resizer-handle' class='inactive-resizer-handle'></p>
                </div>
            </div>

            <!-- Legend to show all symbols -->
            <div class="legend" id="legend-div">
                <div class="sys-var-container">
                    <div class="legend-title-container">
                        <p class="legend-title">Systems &amp;&nbsp;Variables</p>
                    </div>
                    <div id="sys-var-legend"></div>
                </div>
                <div class="n2-symbols-container">
                    <div class="legend-title-container">
                        <p class="legend-title">N2<br />Symbols</p>
                    </div>
                    <div id="symbols-legend">
                        <div class="symbol">
                            <div class="symbol-outer scalar">
                                <div class="symbol-inner"></div>
                            </div>
                            <p>Scalar</p>
                        </div>
                        <div class="symbol">
                            <div class="symbol-outer vector">
                                <div class="symbol-inner"></div>
                            </div>
                            <p>Vector</p>
                        </div>
                        <div class="symbol">
                            <div class="symbol-outer collapsed">
                                <div class="symbol-inner"></div>
                            </div>
                            <p>Collapsed Variables</p>
                        </div>
                    </div>
                </div>
                <div class="linear-solvers-container">
                    <div class="legend-title-container">
                        <p class="legend-title" id="solvers-legend-title">Linear Solvers</p>
                    </div>
                    <div id="solvers-legend"></div>
                </div>
                <div class="draggable">
                    <div id='draggable-legend-dots'>
                        <p class="legend-dots"></p>
                    </div>
                    <div class="icon-key"></div>
                    <div id='draggable-legend-dots'>
                        <p class="legend-dots"></p>
                    </div>
                </div>
                <div id="close-legend">
                    <p></p>
                </div>
            </div>
        </div>
        <div id="connectionId"></div>
    </div>
</div>

<div id="node-info-container" class='info-hidden'>
    <table id="node-info-table" cellpadding='0' cellspacing='0'>
        <thead>
            <tr>
                <th scope='col' colspan='2'>Name</th>
            </tr>
        </thead>
        <tbody></tbody>
        <tfoot>
            <tr>
                <th scope='col' colspan='2'>&nbsp;</th>
            </tr>
        </tfoot>
    </table>
    <p id='node-info-pin' class='info-hidden'>&#x1F4CC;</p>
</div>

<div class="tool-tip" style="position: absolute; visibility: hidden;"></div>
<div id="top" class="offgrid" style="visibility: hidden;"></div>
<div id="left" class="offgrid" style="visibility: hidden;"></div>
<div id="right" class="offgrid" style="visibility: hidden;"></div>
<div id="bottom" class="offgrid" style="visibility: hidden;"></div>

<div id="logo-container">
    <img id="company-logo" alt="OpenMDAO" src="" />
</div>

    <script type="text/javascript">
// https://d3js.org v5.12.0 Copyright 2019 Mike Bostock
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t=t||self).d3=t.d3||{})}(this,function(t){"use strict";function n(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function e(t){var e;return 1===t.length&&(e=t,t=function(t,r){return n(e(t),r)}),{left:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)<0?r=o+1:i=o}return r},right:function(n,e,r,i){for(null==r&&(r=0),null==i&&(i=n.length);r<i;){var o=r+i>>>1;t(n[o],e)>0?i=o:r=o+1}return r}}}var r=e(n),i=r.right,o=r.left;function a(t,n){return[t,n]}function u(t){return null===t?NaN:+t}function c(t,n){var e,r,i=t.length,o=0,a=-1,c=0,f=0;if(null==n)for(;++a<i;)isNaN(e=u(t[a]))||(f+=(r=e-c)*(e-(c+=r/++o)));else for(;++a<i;)isNaN(e=u(n(t[a],a,t)))||(f+=(r=e-c)*(e-(c+=r/++o)));if(o>1)return f/(o-1)}function f(t,n){var e=c(t,n);return e?Math.sqrt(e):e}function s(t,n){var e,r,i,o=t.length,a=-1;if(null==n){for(;++a<o;)if(null!=(e=t[a])&&e>=e)for(r=i=e;++a<o;)null!=(e=t[a])&&(r>e&&(r=e),i<e&&(i=e))}else for(;++a<o;)if(null!=(e=n(t[a],a,t))&&e>=e)for(r=i=e;++a<o;)null!=(e=n(t[a],a,t))&&(r>e&&(r=e),i<e&&(i=e));return[r,i]}var l=Array.prototype,h=l.slice,d=l.map;function p(t){return function(){return t}}function v(t){return t}function g(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}var y=Math.sqrt(50),_=Math.sqrt(10),b=Math.sqrt(2);function m(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=x(t,n,e))||!isFinite(a))return[];if(a>0)for(t=Math.ceil(t/a),n=Math.floor(n/a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)*a;else for(t=Math.floor(t*a),n=Math.ceil(n*a),o=new Array(i=Math.ceil(t-n+1));++u<i;)o[u]=(t-u)/a;return r&&o.reverse(),o}function x(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=y?10:o>=_?5:o>=b?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=y?10:o>=_?5:o>=b?2:1)}function w(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=y?i*=10:o>=_?i*=5:o>=b&&(i*=2),n<t?-i:i}function M(t){return Math.ceil(Math.log(t.length)/Math.LN2)+1}function N(t,n,e){if(null==e&&(e=u),r=t.length){if((n=+n)<=0||r<2)return+e(t[0],0,t);if(n>=1)return+e(t[r-1],r-1,t);var r,i=(r-1)*n,o=Math.floor(i),a=+e(t[o],o,t);return a+(+e(t[o+1],o+1,t)-a)*(i-o)}}function A(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&e>r&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&e>r&&(r=e);return r}function T(t){for(var n,e,r,i=t.length,o=-1,a=0;++o<i;)a+=t[o].length;for(e=new Array(a);--i>=0;)for(n=(r=t[i]).length;--n>=0;)e[--a]=r[n];return e}function S(t,n){var e,r,i=t.length,o=-1;if(null==n){for(;++o<i;)if(null!=(e=t[o])&&e>=e)for(r=e;++o<i;)null!=(e=t[o])&&r>e&&(r=e)}else for(;++o<i;)if(null!=(e=n(t[o],o,t))&&e>=e)for(r=e;++o<i;)null!=(e=n(t[o],o,t))&&r>e&&(r=e);return r}function k(t){if(!(i=t.length))return[];for(var n=-1,e=S(t,E),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function E(t){return t.length}var C=Array.prototype.slice;function P(t){return t}var z=1,R=2,D=3,q=4,L=1e-6;function U(t){return"translate("+(t+.5)+",0)"}function O(t){return"translate(0,"+(t+.5)+")"}function B(){return!this.__axis}function Y(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c=t===z||t===q?-1:1,f=t===q||t===R?"x":"y",s=t===z||t===D?U:O;function l(l){var h=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,d=null==i?n.tickFormat?n.tickFormat.apply(n,e):P:i,p=Math.max(o,0)+u,v=n.range(),g=+v[0]+.5,y=+v[v.length-1]+.5,_=(n.bandwidth?function(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}:function(t){return function(n){return+t(n)}})(n.copy()),b=l.selection?l.selection():l,m=b.selectAll(".domain").data([null]),x=b.selectAll(".tick").data(h,n).order(),w=x.exit(),M=x.enter().append("g").attr("class","tick"),N=x.select("line"),A=x.select("text");m=m.merge(m.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),x=x.merge(M),N=N.merge(M.append("line").attr("stroke","currentColor").attr(f+"2",c*o)),A=A.merge(M.append("text").attr("fill","currentColor").attr(f,c*p).attr("dy",t===z?"0em":t===D?"0.71em":"0.32em")),l!==b&&(m=m.transition(l),x=x.transition(l),N=N.transition(l),A=A.transition(l),w=w.transition(l).attr("opacity",L).attr("transform",function(t){return isFinite(t=_(t))?s(t):this.getAttribute("transform")}),M.attr("opacity",L).attr("transform",function(t){var n=this.parentNode.__axis;return s(n&&isFinite(n=n(t))?n:_(t))})),w.remove(),m.attr("d",t===q||t==R?a?"M"+c*a+","+g+"H0.5V"+y+"H"+c*a:"M0.5,"+g+"V"+y:a?"M"+g+","+c*a+"V0.5H"+y+"V"+c*a:"M"+g+",0.5H"+y),x.attr("opacity",1).attr("transform",function(t){return s(_(t))}),N.attr(f+"2",c*o),A.attr(f,c*p).text(d),b.filter(B).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",t===R?"start":t===q?"end":"middle"),b.each(function(){this.__axis=_})}return l.scale=function(t){return arguments.length?(n=t,l):n},l.ticks=function(){return e=C.call(arguments),l},l.tickArguments=function(t){return arguments.length?(e=null==t?[]:C.call(t),l):e.slice()},l.tickValues=function(t){return arguments.length?(r=null==t?null:C.call(t),l):r&&r.slice()},l.tickFormat=function(t){return arguments.length?(i=t,l):i},l.tickSize=function(t){return arguments.length?(o=a=+t,l):o},l.tickSizeInner=function(t){return arguments.length?(o=+t,l):o},l.tickSizeOuter=function(t){return arguments.length?(a=+t,l):a},l.tickPadding=function(t){return arguments.length?(u=+t,l):u},l}var F={value:function(){}};function I(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r)throw new Error("illegal type: "+t);r[t]=[]}return new H(r)}function H(t){this._=t}function j(t,n){return t.trim().split(/^|\s+/).map(function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})}function X(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function G(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=F,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}H.prototype=I.prototype={constructor:H,on:function(t,n){var e,r=this._,i=j(t+"",r),o=-1,a=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<a;)if(e=(t=i[o]).type)r[e]=G(r[e],t.name,n);else if(null==n)for(e in r)r[e]=G(r[e],t.name,null);return this}for(;++o<a;)if((e=(t=i[o]).type)&&(e=X(r[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new H(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var V="http://www.w3.org/1999/xhtml",$={svg:"http://www.w3.org/2000/svg",xhtml:V,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function W(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),$.hasOwnProperty(n)?{space:$[n],local:t}:t}function Z(t){var n=W(t);return(n.local?function(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}:function(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===V&&n.documentElement.namespaceURI===V?n.createElement(t):n.createElementNS(e,t)}})(n)}function Q(){}function K(t){return null==t?Q:function(){return this.querySelector(t)}}function J(){return[]}function tt(t){return null==t?J:function(){return this.querySelectorAll(t)}}function nt(t){return function(){return this.matches(t)}}function et(t){return new Array(t.length)}function rt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}rt.prototype={constructor:rt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}};var it="$";function ot(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new rt(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function at(t,n,e,r,i,o,a){var u,c,f,s={},l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=it+a.call(c,c.__data__,u,n),f in s?i[u]=c:s[f]=c);for(u=0;u<h;++u)(c=s[f=it+a.call(t,o[u],u,o)])?(r[u]=c,c.__data__=o[u],s[f]=null):e[u]=new rt(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s[d[u]]===c&&(i[u]=c)}function ut(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function ct(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function ft(t,n){return t.style.getPropertyValue(n)||ct(t).getComputedStyle(t,null).getPropertyValue(n)}function st(t){return t.trim().split(/^|\s+/)}function lt(t){return t.classList||new ht(t)}function ht(t){this._node=t,this._names=st(t.getAttribute("class")||"")}function dt(t,n){for(var e=lt(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function pt(t,n){for(var e=lt(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function vt(){this.textContent=""}function gt(){this.innerHTML=""}function yt(){this.nextSibling&&this.parentNode.appendChild(this)}function _t(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function bt(){return null}function mt(){var t=this.parentNode;t&&t.removeChild(this)}function xt(){return this.parentNode.insertBefore(this.cloneNode(!1),this.nextSibling)}function wt(){return this.parentNode.insertBefore(this.cloneNode(!0),this.nextSibling)}ht.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Mt={};(t.event=null,"undefined"!=typeof document)&&("onmouseenter"in document.documentElement||(Mt={mouseenter:"mouseover",mouseleave:"mouseout"}));function Nt(t,n,e){return t=At(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function At(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function Tt(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.capture);++i?n.length=i:delete this.__on}}}function St(t,n,e){var r=Mt.hasOwnProperty(t.type)?Nt:At;return function(i,o,a){var u,c=this.__on,f=r(n,o,a);if(c)for(var s=0,l=c.length;s<l;++s)if((u=c[s]).type===t.type&&u.name===t.name)return this.removeEventListener(u.type,u.listener,u.capture),this.addEventListener(u.type,u.listener=f,u.capture=e),void(u.value=n);this.addEventListener(t.type,f,e),u={type:t.type,name:t.name,value:n,listener:f,capture:e},c?c.push(u):this.__on=[u]}}function kt(n,e,r,i){var o=t.event;n.sourceEvent=t.event,t.event=n;try{return e.apply(r,i)}finally{t.event=o}}function Et(t,n,e){var r=ct(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}var Ct=[null];function Pt(t,n){this._groups=t,this._parents=n}function zt(){return new Pt([[document.documentElement]],Ct)}function Rt(t){return"string"==typeof t?new Pt([[document.querySelector(t)]],[document.documentElement]):new Pt([[t]],Ct)}Pt.prototype=zt.prototype={constructor:Pt,select:function(t){"function"!=typeof t&&(t=K(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new Pt(r,this._parents)},selectAll:function(t){"function"!=typeof t&&(t=tt(t));for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new Pt(r,i)},filter:function(t){"function"!=typeof t&&(t=nt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Pt(r,this._parents)},data:function(t,n){if(!t)return d=new Array(this.size()),f=-1,this.each(function(t){d[++f]=t}),d;var e=n?at:ot,r=this._parents,i=this._groups;"function"!=typeof t&&(t=function(t){return function(){return t}}(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=t.call(s,s&&s.__data__,f,r),p=d.length,v=u[f]=new Array(p),g=a[f]=new Array(p);e(s,l,v,g,c[f]=new Array(h),d,n);for(var y,_,b=0,m=0;b<p;++b)if(y=v[b]){for(b>=m&&(m=b+1);!(_=g[m])&&++m<p;);y._next=_||null}}return(a=new Pt(a,r))._enter=u,a._exit=c,a},enter:function(){return new Pt(this._enter||this._groups.map(et),this._parents)},exit:function(){return new Pt(this._exit||this._groups.map(et),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return r="function"==typeof t?t(r):r.append(t+""),null!=n&&(i=n(i)),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new Pt(a,this._parents)},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=ut);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new Pt(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){var t=0;return this.each(function(){++t}),t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=W(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}}:"function"==typeof n?e.local?function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}:function(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}:e.local?function(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}:function(t,n){return function(){this.setAttribute(t,n)}})(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?function(t){return function(){this.style.removeProperty(t)}}:"function"==typeof n?function(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}:function(t,n,e){return function(){this.style.setProperty(t,n,e)}})(t,n,null==e?"":e)):ft(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?function(t){return function(){delete this[t]}}:"function"==typeof n?function(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}:function(t,n){return function(){this[t]=n}})(t,n)):this.node()[t]},classed:function(t,n){var e=st(t+"");if(arguments.length<2){for(var r=lt(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?function(t,n){return function(){(n.apply(this,arguments)?dt:pt)(this,t)}}:n?function(t){return function(){dt(this,t)}}:function(t){return function(){pt(this,t)}})(e,n))},text:function(t){return arguments.length?this.each(null==t?vt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}:function(t){return function(){this.textContent=t}})(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?gt:("function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}:function(t){return function(){this.innerHTML=t}})(t)):this.node().innerHTML},raise:function(){return this.each(yt)},lower:function(){return this.each(_t)},append:function(t){var n="function"==typeof t?t:Z(t);return this.select(function(){return this.appendChild(n.apply(this,arguments))})},insert:function(t,n){var e="function"==typeof t?t:Z(t),r=null==n?bt:"function"==typeof n?n:K(n);return this.select(function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)})},remove:function(){return this.each(mt)},clone:function(t){return this.select(t?wt:xt)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=function(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?St:Tt,null==e&&(e=!1),r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?function(t,n){return function(){return Et(this,t,n.apply(this,arguments))}}:function(t,n){return function(){return Et(this,t,n)}})(t,n))}};var Dt=0;function qt(){return new Lt}function Lt(){this._="@"+(++Dt).toString(36)}function Ut(){for(var n,e=t.event;n=e.sourceEvent;)e=n;return e}function Ot(t,n){var e=t.ownerSVGElement||t;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=n.clientX,r.y=n.clientY,[(r=r.matrixTransform(t.getScreenCTM().inverse())).x,r.y]}var i=t.getBoundingClientRect();return[n.clientX-i.left-t.clientLeft,n.clientY-i.top-t.clientTop]}function Bt(t){var n=Ut();return n.changedTouches&&(n=n.changedTouches[0]),Ot(t,n)}function Yt(t,n,e){arguments.length<3&&(e=n,n=Ut().changedTouches);for(var r,i=0,o=n?n.length:0;i<o;++i)if((r=n[i]).identifier===e)return Ot(t,r);return null}function Ft(){t.event.stopImmediatePropagation()}function It(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function Ht(t){var n=t.document.documentElement,e=Rt(t).on("dragstart.drag",It,!0);"onselectstart"in n?e.on("selectstart.drag",It,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function jt(t,n){var e=t.document.documentElement,r=Rt(t).on("dragstart.drag",null);n&&(r.on("click.drag",It,!0),setTimeout(function(){r.on("click.drag",null)},0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}function Xt(t){return function(){return t}}function Gt(t,n,e,r,i,o,a,u,c,f){this.target=t,this.type=n,this.subject=e,this.identifier=r,this.active=i,this.x=o,this.y=a,this.dx=u,this.dy=c,this._=f}function Vt(){return!t.event.ctrlKey&&!t.event.button}function $t(){return this.parentNode}function Wt(n){return null==n?{x:t.event.x,y:t.event.y}:n}function Zt(){return navigator.maxTouchPoints||"ontouchstart"in this}function Qt(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function Kt(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Jt(){}Lt.prototype=qt.prototype={constructor:Lt,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}},Gt.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var tn="\\s*([+-]?\\d+)\\s*",nn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",en="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",rn=/^#([0-9a-f]{3})$/,on=/^#([0-9a-f]{6})$/,an=new RegExp("^rgb\\("+[tn,tn,tn]+"\\)$"),un=new RegExp("^rgb\\("+[en,en,en]+"\\)$"),cn=new RegExp("^rgba\\("+[tn,tn,tn,nn]+"\\)$"),fn=new RegExp("^rgba\\("+[en,en,en,nn]+"\\)$"),sn=new RegExp("^hsl\\("+[nn,en,en]+"\\)$"),ln=new RegExp("^hsla\\("+[nn,en,en,nn]+"\\)$"),hn={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function dn(){return this.rgb().formatHex()}function pn(){return this.rgb().formatRgb()}function vn(t){var n;return t=(t+"").trim().toLowerCase(),(n=rn.exec(t))?new mn((n=parseInt(n[1],16))>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=on.exec(t))?gn(parseInt(n[1],16)):(n=an.exec(t))?new mn(n[1],n[2],n[3],1):(n=un.exec(t))?new mn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=cn.exec(t))?yn(n[1],n[2],n[3],n[4]):(n=fn.exec(t))?yn(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=sn.exec(t))?Nn(n[1],n[2]/100,n[3]/100,1):(n=ln.exec(t))?Nn(n[1],n[2]/100,n[3]/100,n[4]):hn.hasOwnProperty(t)?gn(hn[t]):"transparent"===t?new mn(NaN,NaN,NaN,0):null}function gn(t){return new mn(t>>16&255,t>>8&255,255&t,1)}function yn(t,n,e,r){return r<=0&&(t=n=e=NaN),new mn(t,n,e,r)}function _n(t){return t instanceof Jt||(t=vn(t)),t?new mn((t=t.rgb()).r,t.g,t.b,t.opacity):new mn}function bn(t,n,e,r){return 1===arguments.length?_n(t):new mn(t,n,e,null==r?1:r)}function mn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function xn(){return"#"+Mn(this.r)+Mn(this.g)+Mn(this.b)}function wn(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function Mn(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function Nn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new Sn(t,n,e,r)}function An(t){if(t instanceof Sn)return new Sn(t.h,t.s,t.l,t.opacity);if(t instanceof Jt||(t=vn(t)),!t)return new Sn;if(t instanceof Sn)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new Sn(a,u,c,t.opacity)}function Tn(t,n,e,r){return 1===arguments.length?An(t):new Sn(t,n,e,null==r?1:r)}function Sn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function kn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Qt(Jt,vn,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:dn,formatHex:dn,formatHsl:function(){return An(this).formatHsl()},formatRgb:pn,toString:pn}),Qt(mn,bn,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new mn(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new mn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:xn,formatHex:xn,formatRgb:wn,toString:wn})),Qt(Sn,Tn,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new Sn(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new Sn(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new mn(kn(t>=240?t-240:t+120,i,r),kn(t,i,r),kn(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));var En=Math.PI/180,Cn=180/Math.PI,Pn=.96422,zn=1,Rn=.82521,Dn=4/29,qn=6/29,Ln=3*qn*qn,Un=qn*qn*qn;function On(t){if(t instanceof Yn)return new Yn(t.l,t.a,t.b,t.opacity);if(t instanceof Vn)return $n(t);t instanceof mn||(t=_n(t));var n,e,r=jn(t.r),i=jn(t.g),o=jn(t.b),a=Fn((.2225045*r+.7168786*i+.0606169*o)/zn);return r===i&&i===o?n=e=a:(n=Fn((.4360747*r+.3850649*i+.1430804*o)/Pn),e=Fn((.0139322*r+.0971045*i+.7141733*o)/Rn)),new Yn(116*a-16,500*(n-a),200*(a-e),t.opacity)}function Bn(t,n,e,r){return 1===arguments.length?On(t):new Yn(t,n,e,null==r?1:r)}function Yn(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function Fn(t){return t>Un?Math.pow(t,1/3):t/Ln+Dn}function In(t){return t>qn?t*t*t:Ln*(t-Dn)}function Hn(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function jn(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function Xn(t){if(t instanceof Vn)return new Vn(t.h,t.c,t.l,t.opacity);if(t instanceof Yn||(t=On(t)),0===t.a&&0===t.b)return new Vn(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*Cn;return new Vn(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function Gn(t,n,e,r){return 1===arguments.length?Xn(t):new Vn(t,n,e,null==r?1:r)}function Vn(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function $n(t){if(isNaN(t.h))return new Yn(t.l,0,0,t.opacity);var n=t.h*En;return new Yn(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}Qt(Yn,Bn,Kt(Jt,{brighter:function(t){return new Yn(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Yn(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new mn(Hn(3.1338561*(n=Pn*In(n))-1.6168667*(t=zn*In(t))-.4906146*(e=Rn*In(e))),Hn(-.9787684*n+1.9161415*t+.033454*e),Hn(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Qt(Vn,Gn,Kt(Jt,{brighter:function(t){return new Vn(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new Vn(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return $n(this).rgb()}}));var Wn=-.14861,Zn=1.78277,Qn=-.29227,Kn=-.90649,Jn=1.97294,te=Jn*Kn,ne=Jn*Zn,ee=Zn*Qn-Kn*Wn;function re(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof ie)return new ie(t.h,t.s,t.l,t.opacity);t instanceof mn||(t=_n(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(ee*r+te*n-ne*e)/(ee+te-ne),o=r-i,a=(Jn*(e-i)-Qn*o)/Kn,u=Math.sqrt(a*a+o*o)/(Jn*i*(1-i)),c=u?Math.atan2(a,o)*Cn-120:NaN;return new ie(c<0?c+360:c,u,i,t.opacity)}(t):new ie(t,n,e,null==r?1:r)}function ie(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function oe(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function ae(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return oe((e-r/n)*n,a,i,o,u)}}function ue(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return oe((e-r/n)*n,i,o,a,u)}}function ce(t){return function(){return t}}function fe(t,n){return function(e){return t+e*n}}function se(t,n){var e=n-t;return e?fe(t,e>180||e<-180?e-360*Math.round(e/360):e):ce(isNaN(t)?n:t)}function le(t){return 1==(t=+t)?he:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):ce(isNaN(n)?e:n)}}function he(t,n){var e=n-t;return e?fe(t,e):ce(isNaN(t)?n:t)}Qt(ie,re,Kt(Jt,{brighter:function(t){return t=null==t?1/.7:Math.pow(1/.7,t),new ie(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?.7:Math.pow(.7,t),new ie(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*En,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new mn(255*(n+e*(Wn*r+Zn*i)),255*(n+e*(Qn*r+Kn*i)),255*(n+e*(Jn*r)),this.opacity)}}));var de=function t(n){var e=le(n);function r(t,n){var r=e((t=bn(t)).r,(n=bn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=he(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function pe(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=bn(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var ve=pe(ae),ge=pe(ue);function ye(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=Ne(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function _e(t,n){var e=new Date;return n-=t=+t,function(r){return e.setTime(t+n*r),e}}function be(t,n){return n-=t=+t,function(e){return t+n*e}}function me(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=Ne(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var xe=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,we=new RegExp(xe.source,"g");function Me(t,n){var e,r,i,o=xe.lastIndex=we.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=xe.exec(t))&&(r=we.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:be(e,r)})),o=we.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function Ne(t,n){var e,r=typeof n;return null==n||"boolean"===r?ce(n):("number"===r?be:"string"===r?(e=vn(n))?(n=e,de):Me:n instanceof vn?de:n instanceof Date?_e:Array.isArray(n)?ye:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?me:be)(t,n)}function Ae(t,n){return n-=t=+t,function(e){return Math.round(t+n*e)}}var Te,Se,ke,Ee,Ce=180/Math.PI,Pe={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function ze(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*Ce,skewX:Math.atan(c)*Ce,scaleX:a,scaleY:u}}function Re(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:be(t,i)},{i:c-2,x:be(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:be(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:be(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:be(t,e)},{i:u-2,x:be(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var De=Re(function(t){return"none"===t?Pe:(Te||(Te=document.createElement("DIV"),Se=document.documentElement,ke=document.defaultView),Te.style.transform=t,t=ke.getComputedStyle(Se.appendChild(Te),null).getPropertyValue("transform"),Se.removeChild(Te),ze(+(t=t.slice(7,-1).split(","))[0],+t[1],+t[2],+t[3],+t[4],+t[5]))},"px, ","px)","deg)"),qe=Re(function(t){return null==t?Pe:(Ee||(Ee=document.createElementNS("http://www.w3.org/2000/svg","g")),Ee.setAttribute("transform",t),(t=Ee.transform.baseVal.consolidate())?ze((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):Pe)},", ",")",")"),Le=Math.SQRT2,Ue=2,Oe=4,Be=1e-12;function Ye(t){return((t=Math.exp(t))+1/t)/2}function Fe(t,n){var e,r,i=t[0],o=t[1],a=t[2],u=n[0],c=n[1],f=n[2],s=u-i,l=c-o,h=s*s+l*l;if(h<Be)r=Math.log(f/a)/Le,e=function(t){return[i+t*s,o+t*l,a*Math.exp(Le*t*r)]};else{var d=Math.sqrt(h),p=(f*f-a*a+Oe*h)/(2*a*Ue*d),v=(f*f-a*a-Oe*h)/(2*f*Ue*d),g=Math.log(Math.sqrt(p*p+1)-p),y=Math.log(Math.sqrt(v*v+1)-v);r=(y-g)/Le,e=function(t){var n=t*r,e=Ye(g),u=a/(Ue*d)*(e*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(Le*n+g)-function(t){return((t=Math.exp(t))-1/t)/2}(g));return[i+u*s,o+u*l,a*e/Ye(Le*n+g)]}}return e.duration=1e3*r,e}function Ie(t){return function(n,e){var r=t((n=Tn(n)).h,(e=Tn(e)).h),i=he(n.s,e.s),o=he(n.l,e.l),a=he(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var He=Ie(se),je=Ie(he);function Xe(t){return function(n,e){var r=t((n=Gn(n)).h,(e=Gn(e)).h),i=he(n.c,e.c),o=he(n.l,e.l),a=he(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Ge=Xe(se),Ve=Xe(he);function $e(t){return function n(e){function r(n,r){var i=t((n=re(n)).h,(r=re(r)).h),o=he(n.s,r.s),a=he(n.l,r.l),u=he(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var We=$e(se),Ze=$e(he);var Qe,Ke,Je=0,tr=0,nr=0,er=1e3,rr=0,ir=0,or=0,ar="object"==typeof performance&&performance.now?performance:Date,ur="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function cr(){return ir||(ur(fr),ir=ar.now()+or)}function fr(){ir=0}function sr(){this._call=this._time=this._next=null}function lr(t,n,e){var r=new sr;return r.restart(t,n,e),r}function hr(){cr(),++Je;for(var t,n=Qe;n;)(t=ir-n._time)>=0&&n._call.call(null,t),n=n._next;--Je}function dr(){ir=(rr=ar.now())+or,Je=tr=0;try{hr()}finally{Je=0,function(){var t,n,e=Qe,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Qe=n);Ke=t,vr(r)}(),ir=0}}function pr(){var t=ar.now(),n=t-rr;n>er&&(or-=n,rr=t)}function vr(t){Je||(tr&&(tr=clearTimeout(tr)),t-ir>24?(t<1/0&&(tr=setTimeout(dr,t-ar.now()-or)),nr&&(nr=clearInterval(nr))):(nr||(rr=ar.now(),nr=setInterval(pr,er)),Je=1,ur(dr)))}function gr(t,n,e){var r=new sr;return n=null==n?0:+n,r.restart(function(e){r.stop(),t(e+n)},n,e),r}sr.prototype=lr.prototype={constructor:sr,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?cr():+e)+(null==n?0:+n),this._next||Ke===this||(Ke?Ke._next=this:Qe=this,Ke=this),this._call=t,this._time=e,vr()},stop:function(){this._call&&(this._call=null,this._time=1/0,vr())}};var yr=I("start","end","cancel","interrupt"),_r=[],br=0,mr=1,xr=2,wr=3,Mr=4,Nr=5,Ar=6;function Tr(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(c){var f,s,l,h;if(e.state!==mr)return u();for(f in i)if((h=i[f]).name===e.name){if(h.state===wr)return gr(o);h.state===Mr?(h.state=Ar,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=Ar,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if(gr(function(){e.state===wr&&(e.state=Mr,e.timer.restart(a,e.delay,e.time),a(c))}),e.state=xr,e.on.call("start",t,t.__data__,e.index,e.group),e.state===xr){for(e.state=wr,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function a(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(u),e.state=Nr,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);e.state===Nr&&(e.on.call("end",t,t.__data__,e.index,e.group),u())}function u(){for(var r in e.state=Ar,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=lr(function(t){e.state=mr,e.timer.restart(o,e.delay,e.time),e.delay<=t&&o(t-e.delay)},0,e.time)}(t,e,{name:n,index:r,group:i,on:yr,tween:_r,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:br})}function Sr(t,n){var e=Er(t,n);if(e.state>br)throw new Error("too late; already scheduled");return e}function kr(t,n){var e=Er(t,n);if(e.state>wr)throw new Error("too late; already running");return e}function Er(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function Cr(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>xr&&e.state<Nr,e.state=Ar,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function Pr(t,n,e){var r=t._id;return t.each(function(){var t=kr(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)}),function(t){return Er(t,r).value[n]}}function zr(t,n){var e;return("number"==typeof n?be:n instanceof vn?de:(e=vn(n))?(n=e,de):Me)(t,n)}var Rr=zt.prototype.constructor;function Dr(t){return function(){this.style.removeProperty(t)}}var qr=0;function Lr(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Ur(t){return zt().transition(t)}function Or(){return++qr}var Br=zt.prototype;function Yr(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function Fr(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}Lr.prototype=Ur.prototype={constructor:Lr,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=K(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,Tr(l[h],n,e,h,l,Er(u,e)));return new Lr(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=tt(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=Er(c,e),v=0,g=d.length;v<g;++v)(h=d[v])&&Tr(h,n,e,v,d,p);o.push(d),a.push(c)}return new Lr(o,a,n,e)},filter:function(t){"function"!=typeof t&&(t=nt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new Lr(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new Lr(a,this._parents,this._name,this._id)},selection:function(){return new Rr(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Or(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=Er(a,n);Tr(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new Lr(r,this._parents,t,e)},call:Br.call,nodes:Br.nodes,node:Br.node,size:Br.size,empty:Br.empty,each:Br.each,on:function(t,n){var e=this._id;return arguments.length<2?Er(this.node(),e).on.on(t):this.each(function(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every(function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t})}(n)?Sr:kr;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=W(t),r="transform"===e?qe:zr;return this.attrTween(t,"function"==typeof n?(e.local?function(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}:function(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}})(e,r,Pr(this,"attr."+t,n)):null==n?(e.local?function(t){return function(){this.removeAttributeNS(t.space,t.local)}}:function(t){return function(){this.removeAttribute(t)}})(e):(e.local?function(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}:function(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}})(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=W(t);return this.tween(e,(r.local?function(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttributeNS(t.space,t.local,n(e))}}(t,i)),e}return i._value=n,i}:function(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&function(t,n){return function(e){this.setAttribute(t,n(e))}}(t,i)),e}return i._value=n,i})(r,n))},style:function(t,n,e){var r="transform"==(t+="")?De:zr;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=ft(this,t),a=(this.style.removeProperty(t),ft(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,Dr(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=ft(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=ft(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,Pr(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=kr(this,t),f=c.on,s=null==c.value[a]?o||(o=Dr(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=ft(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n(r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(Pr(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=Er(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?function(t,n){var e,r;return function(){var i=kr(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}:function(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=kr(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}})(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){Sr(this,t).delay=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){Sr(this,t).delay=n}})(n,t)):Er(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?function(t,n){return function(){kr(this,t).duration=+n.apply(this,arguments)}}:function(t,n){return n=+n,function(){kr(this,t).duration=n}})(n,t)):Er(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(function(t,n){if("function"!=typeof n)throw new Error;return function(){kr(this,t).ease=n}}(n,t)):Er(this.node(),n).ease},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise(function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each(function(){var e=kr(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})})}};var Ir=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Hr=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),jr=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),Xr=Math.PI,Gr=Xr/2;function Vr(t){return(1-Math.cos(Xr*t))/2}function $r(t){return((t*=2)<=1?Math.pow(2,10*t-10):2-Math.pow(2,10-10*t))/2}function Wr(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Zr=4/11,Qr=6/11,Kr=8/11,Jr=.75,ti=9/11,ni=10/11,ei=.9375,ri=21/22,ii=63/64,oi=1/Zr/Zr;function ai(t){return(t=+t)<Zr?oi*t*t:t<Kr?oi*(t-=Qr)*t+Jr:t<ni?oi*(t-=ti)*t+ei:oi*(t-=ri)*t+ii}var ui=function t(n){function e(t){return t*t*((n+1)*t-n)}return n=+n,e.overshoot=t,e}(1.70158),ci=function t(n){function e(t){return--t*t*((n+1)*t+n)+1}return n=+n,e.overshoot=t,e}(1.70158),fi=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(1.70158),si=2*Math.PI,li=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=si);function i(t){return n*Math.pow(2,10*--t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*si)},i.period=function(e){return t(n,e)},i}(1,.3),hi=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=si);function i(t){return 1-n*Math.pow(2,-10*(t=+t))*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*si)},i.period=function(e){return t(n,e)},i}(1,.3),di=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=si);function i(t){return((t=2*t-1)<0?n*Math.pow(2,10*t)*Math.sin((r-t)/e):2-n*Math.pow(2,-10*t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*si)},i.period=function(e){return t(n,e)},i}(1,.3),pi={time:null,delay:0,duration:250,ease:Fr};function vi(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))return pi.time=cr(),pi;return e}zt.prototype.interrupt=function(t){return this.each(function(){Cr(this,t)})},zt.prototype.transition=function(t){var n,e;t instanceof Lr?(n=t._id,t=t._name):(n=Or(),(e=pi).time=cr(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&Tr(a,t,n,f,u,e||vi(a,n));return new Lr(r,this._parents,t,n)};var gi=[null];function yi(t){return function(){return t}}function _i(t,n,e){this.target=t,this.type=n,this.selection=e}function bi(){t.event.stopImmediatePropagation()}function mi(){t.event.preventDefault(),t.event.stopImmediatePropagation()}var xi={name:"drag"},wi={name:"space"},Mi={name:"handle"},Ni={name:"center"};function Ai(t){return[+t[0],+t[1]]}function Ti(t){return[Ai(t[0]),Ai(t[1])]}var Si={name:"x",handles:["w","e"].map(qi),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},ki={name:"y",handles:["n","s"].map(qi),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},Ei={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(qi),input:function(t){return null==t?null:Ti(t)},output:function(t){return t}},Ci={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Pi={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},zi={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},Ri={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Di={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function qi(t){return{type:t}}function Li(){return!t.event.ctrlKey&&!t.event.button}function Ui(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function Oi(){return navigator.maxTouchPoints||"ontouchstart"in this}function Bi(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Yi(n){var e,r=Ui,i=Li,o=Oi,a=!0,u=I(f,"start","brush","end"),c=6;function f(t){var e=t.property("__brush",g).selectAll(".overlay").data([qi("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",Ci.overlay).merge(e).each(function(){var t=Bi(this).extent;Rt(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])}),t.selectAll(".selection").data([qi("selection")]).enter().append("rect").attr("class","selection").attr("cursor",Ci.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=t.selectAll(".handle").data(n.handles,function(t){return t.type});r.exit().remove(),r.enter().append("rect").attr("class",function(t){return"handle handle--"+t.type}).attr("cursor",function(t){return Ci[t.type]}),t.each(s).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",d).filter(o).on("touchstart.brush",d).on("touchmove.brush",p).on("touchend.brush touchcancel.brush",v).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function s(){var t=Rt(this),n=Bi(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",function(t){return"e"===t.type[t.type.length-1]?n[1][0]-c/2:n[0][0]-c/2}).attr("y",function(t){return"s"===t.type[0]?n[1][1]-c/2:n[0][1]-c/2}).attr("width",function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+c:c}).attr("height",function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+c:c})):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function l(t,n,e){return!e&&t.__brush.emitter||new h(t,n)}function h(t,n){this.that=t,this.args=n,this.state=t.__brush,this.active=0}function d(){if((!e||t.event.touches)&&i.apply(this,arguments)){var r,o,u,c,f,h,d,p,v,g,y,_,b=this,m=t.event.target.__data__.type,x="selection"===(a&&t.event.metaKey?m="overlay":m)?xi:a&&t.event.altKey?Ni:Mi,w=n===ki?null:Ri[m],M=n===Si?null:Di[m],N=Bi(b),A=N.extent,T=N.selection,S=A[0][0],k=A[0][1],E=A[1][0],C=A[1][1],P=0,z=0,R=w&&M&&a&&t.event.shiftKey,D=t.event.touches?(_=t.event.changedTouches[0].identifier,function(n){return Yt(n,t.event.touches,_)}):Bt,q=D(b),L=q,U=l(b,arguments,!0).beforestart();"overlay"===m?(T&&(v=!0),N.selection=T=[[r=n===ki?S:q[0],u=n===Si?k:q[1]],[f=n===ki?E:r,d=n===Si?C:u]]):(r=T[0][0],u=T[0][1],f=T[1][0],d=T[1][1]),o=r,c=u,h=f,p=d;var O=Rt(b).attr("pointer-events","none"),B=O.selectAll(".overlay").attr("cursor",Ci[m]);if(t.event.touches)U.moved=F,U.ended=H;else{var Y=Rt(t.event.view).on("mousemove.brush",F,!0).on("mouseup.brush",H,!0);a&&Y.on("keydown.brush",function(){switch(t.event.keyCode){case 16:R=w&&M;break;case 18:x===Mi&&(w&&(f=h-P*w,r=o+P*w),M&&(d=p-z*M,u=c+z*M),x=Ni,I());break;case 32:x!==Mi&&x!==Ni||(w<0?f=h-P:w>0&&(r=o-P),M<0?d=p-z:M>0&&(u=c-z),x=wi,B.attr("cursor",Ci.selection),I());break;default:return}mi()},!0).on("keyup.brush",function(){switch(t.event.keyCode){case 16:R&&(g=y=R=!1,I());break;case 18:x===Ni&&(w<0?f=h:w>0&&(r=o),M<0?d=p:M>0&&(u=c),x=Mi,I());break;case 32:x===wi&&(t.event.altKey?(w&&(f=h-P*w,r=o+P*w),M&&(d=p-z*M,u=c+z*M),x=Ni):(w<0?f=h:w>0&&(r=o),M<0?d=p:M>0&&(u=c),x=Mi),B.attr("cursor",Ci[m]),I());break;default:return}mi()},!0),Ht(t.event.view)}bi(),Cr(b),s.call(b),U.start()}function F(){var t=D(b);!R||g||y||(Math.abs(t[0]-L[0])>Math.abs(t[1]-L[1])?y=!0:g=!0),L=t,v=!0,mi(),I()}function I(){var t;switch(P=L[0]-q[0],z=L[1]-q[1],x){case wi:case xi:w&&(P=Math.max(S-r,Math.min(E-f,P)),o=r+P,h=f+P),M&&(z=Math.max(k-u,Math.min(C-d,z)),c=u+z,p=d+z);break;case Mi:w<0?(P=Math.max(S-r,Math.min(E-r,P)),o=r+P,h=f):w>0&&(P=Math.max(S-f,Math.min(E-f,P)),o=r,h=f+P),M<0?(z=Math.max(k-u,Math.min(C-u,z)),c=u+z,p=d):M>0&&(z=Math.max(k-d,Math.min(C-d,z)),c=u,p=d+z);break;case Ni:w&&(o=Math.max(S,Math.min(E,r-P*w)),h=Math.max(S,Math.min(E,f+P*w))),M&&(c=Math.max(k,Math.min(C,u-z*M)),p=Math.max(k,Math.min(C,d+z*M)))}h<o&&(w*=-1,t=r,r=f,f=t,t=o,o=h,h=t,m in Pi&&B.attr("cursor",Ci[m=Pi[m]])),p<c&&(M*=-1,t=u,u=d,d=t,t=c,c=p,p=t,m in zi&&B.attr("cursor",Ci[m=zi[m]])),N.selection&&(T=N.selection),g&&(o=T[0][0],h=T[1][0]),y&&(c=T[0][1],p=T[1][1]),T[0][0]===o&&T[0][1]===c&&T[1][0]===h&&T[1][1]===p||(N.selection=[[o,c],[h,p]],s.call(b),U.brush())}function H(){if(bi(),t.event.touches){if(t.event.touches.length)return;e&&clearTimeout(e),e=setTimeout(function(){e=null},500)}else jt(t.event.view,v),Y.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);O.attr("pointer-events","all"),B.attr("cursor",Ci.overlay),N.selection&&(T=N.selection),function(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}(T)&&(N.selection=null,s.call(b)),U.end()}}function p(){l(this,arguments).moved()}function v(){l(this,arguments).ended()}function g(){var t=this.__brush||{selection:null};return t.extent=Ti(r.apply(this,arguments)),t.dim=n,t}return f.move=function(t,e){t.selection?t.on("start.brush",function(){l(this,arguments).beforestart().start()}).on("interrupt.brush end.brush",function(){l(this,arguments).end()}).tween("brush",function(){var t=this,r=t.__brush,i=l(t,arguments),o=r.selection,a=n.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=Ne(o,a);function c(n){r.selection=1===n&&null===a?null:u(n),s.call(t),i.brush()}return null!==o&&null!==a?c:c(1)}):t.each(function(){var t=this,r=arguments,i=t.__brush,o=n.input("function"==typeof e?e.apply(t,r):e,i.extent),a=l(t,r).beforestart();Cr(t),i.selection=null===o?null:o,s.call(t),a.start().brush().end()})},f.clear=function(t){f.move(t,null)},h.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(){return this.starting?(this.starting=!1,this.emit("start")):this.emit("brush"),this},brush:function(){return this.emit("brush"),this},end:function(){return 0==--this.active&&(delete this.state.emitter,this.emit("end")),this},emit:function(t){kt(new _i(f,t,n.output(this.state.selection)),u.apply,u,[t,this.that,this.args])}},f.extent=function(t){return arguments.length?(r="function"==typeof t?t:yi(Ti(t)),f):r},f.filter=function(t){return arguments.length?(i="function"==typeof t?t:yi(!!t),f):i},f.handleSize=function(t){return arguments.length?(c=+t,f):c},f.keyModifiers=function(t){return arguments.length?(a=!!t,f):a},f.on=function(){var t=u.on.apply(u,arguments);return t===u?f:t},f}var Fi=Math.cos,Ii=Math.sin,Hi=Math.PI,ji=Hi/2,Xi=2*Hi,Gi=Math.max;function Vi(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}var $i=Array.prototype.slice;function Wi(t){return function(){return t}}var Zi=Math.PI,Qi=2*Zi,Ki=Qi-1e-6;function Ji(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function to(){return new Ji}function no(t){return t.source}function eo(t){return t.target}function ro(t){return t.radius}function io(t){return t.startAngle}function oo(t){return t.endAngle}Ji.prototype=to.prototype={constructor:Ji,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>1e-6)if(Math.abs(s*u-c*f)>1e-6&&i){var h=e-o,d=r-a,p=u*u+c*c,v=h*h+d*d,g=Math.sqrt(p),y=Math.sqrt(l),_=i*Math.tan((Zi-Math.acos((p+l-v)/(2*g*y)))/2),b=_/y,m=_/g;Math.abs(b-1)>1e-6&&(this._+="L"+(t+b*f)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>f*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,o=!!o;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+f:(Math.abs(this._x1-c)>1e-6||Math.abs(this._y1-f)>1e-6)&&(this._+="L"+c+","+f),e&&(l<0&&(l=l%Qi+Qi),l>Ki?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=c)+","+(this._y1=f):l>1e-6&&(this._+="A"+e+","+e+",0,"+ +(l>=Zi)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};function ao(){}function uo(t,n){var e=new ao;if(t instanceof ao)t.each(function(t,n){e.set(n,t)});else if(Array.isArray(t)){var r,i=-1,o=t.length;if(null==n)for(;++i<o;)e.set(i,t[i]);else for(;++i<o;)e.set(n(r=t[i],i,t),r)}else if(t)for(var a in t)e.set(a,t[a]);return e}function co(){return{}}function fo(t,n,e){t[n]=e}function so(){return uo()}function lo(t,n,e){t.set(n,e)}function ho(){}ao.prototype=uo.prototype={constructor:ao,has:function(t){return"$"+t in this},get:function(t){return this["$"+t]},set:function(t,n){return this["$"+t]=n,this},remove:function(t){var n="$"+t;return n in this&&delete this[n]},clear:function(){for(var t in this)"$"===t[0]&&delete this[t]},keys:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(n.slice(1));return t},values:function(){var t=[];for(var n in this)"$"===n[0]&&t.push(this[n]);return t},entries:function(){var t=[];for(var n in this)"$"===n[0]&&t.push({key:n.slice(1),value:this[n]});return t},size:function(){var t=0;for(var n in this)"$"===n[0]&&++t;return t},empty:function(){for(var t in this)if("$"===t[0])return!1;return!0},each:function(t){for(var n in this)"$"===n[0]&&t(this[n],n.slice(1),this)}};var po=uo.prototype;function vo(t,n){var e=new ho;if(t instanceof ho)t.each(function(t){e.add(t)});else if(t){var r=-1,i=t.length;if(null==n)for(;++r<i;)e.add(t[r]);else for(;++r<i;)e.add(n(t[r],r,t))}return e}ho.prototype=vo.prototype={constructor:ho,has:po.has,add:function(t){return this["$"+(t+="")]=t,this},remove:po.remove,clear:po.clear,values:po.keys,size:po.size,empty:po.empty,each:po.each};var go=Array.prototype.slice;function yo(t,n){return t-n}function _o(t){return function(){return t}}function bo(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=mo(t,n[r]))return e;return 0}function mo(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(xo(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function xo(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function wo(){}var Mo=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function No(){var t=1,n=1,e=M,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(yo);else{var r=s(t),i=r[0],a=r[1];n=w(i,a,n),n=g(Math.floor(i/n)*n,Math.floor(a/n)*n,n)}return n.map(function(n){return o(t,n)})}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=e[0]>=r,Mo[f<<1].forEach(p);for(;++o<t-1;)c=f,f=e[o+1]>=r,Mo[c|f<<1].forEach(p);Mo[f<<0].forEach(p);for(;++u<n-1;){for(o=-1,f=e[u*t+t]>=r,s=e[u*t]>=r,Mo[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,Mo[c|f<<1|s<<2|l<<3].forEach(p);Mo[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,Mo[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,Mo[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}Mo[s<<3].forEach(p)}(e,i,function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)}),u.forEach(function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==bo((n=o[e])[0],t))return void n.push(t)}),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach(function(e){var o,a=e[0],u=e[1],c=0|a,f=0|u,s=r[f*t+c];a>0&&a<t&&c===a&&(o=r[f*t+c-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&f===u&&(o=r[(f-1)*t+c],e[1]=u+(i-o)/(s-o)-.5)})}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.ceil(e[0]),o=Math.ceil(e[1]);if(!(r>0&&o>0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?_o(go.call(t)):_o(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:wo,i):r===u},i}function Ao(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<i;++a)for(var u=0,c=0;u<r+e;++u)u<r&&(c+=t.data[u+a*r]),u>=e&&(u>=o&&(c-=t.data[u-o+a*r]),n.data[u-e+a*r]=c/Math.min(u+1,r-1+o-u,o))}function To(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<r;++a)for(var u=0,c=0;u<i+e;++u)u<i&&(c+=t.data[a+u*r]),u>=e&&(u>=o&&(c-=t.data[a+(u-o)*r]),n.data[a+(u-e)*r]=c/Math.min(u+1,i-1+o-u,o))}function So(t){return t[0]}function ko(t){return t[1]}function Eo(){return 1}var Co={},Po={},zo=34,Ro=10,Do=13;function qo(t){return new Function("d","return {"+t.map(function(t,n){return JSON.stringify(t)+": d["+n+"]"}).join(",")+"}")}function Lo(t){var n=Object.create(null),e=[];return t.forEach(function(t){for(var r in t)r in n||e.push(n[r]=r)}),e}function Uo(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Oo(t){var n=t.getUTCHours(),e=t.getUTCMinutes(),r=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":function(t){return t<0?"-"+Uo(-t,6):t>9999?"+"+Uo(t,6):Uo(t,4)}(t.getUTCFullYear())+"-"+Uo(t.getUTCMonth()+1,2)+"-"+Uo(t.getUTCDate(),2)+(i?"T"+Uo(n,2)+":"+Uo(e,2)+":"+Uo(r,2)+"."+Uo(i,3)+"Z":r?"T"+Uo(n,2)+":"+Uo(e,2)+":"+Uo(r,2)+"Z":e||n?"T"+Uo(n,2)+":"+Uo(e,2)+"Z":"")}function Bo(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return Po;if(f)return f=!1,Co;var n,r,i=a;if(t.charCodeAt(i)===zo){for(;a++<o&&t.charCodeAt(a)!==zo||t.charCodeAt(++a)===zo;);return(n=a)>=o?c=!0:(r=t.charCodeAt(a++))===Ro?f=!0:r===Do&&(f=!0,t.charCodeAt(a)===Ro&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if((r=t.charCodeAt(n=a++))===Ro)f=!0;else if(r===Do)f=!0,t.charCodeAt(a)===Ro&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(t.charCodeAt(o-1)===Ro&&--o,t.charCodeAt(o-1)===Do&&--o;(r=s())!==Po;){for(var l=[];r!==Co&&r!==Po;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map(function(n){return e.map(function(t){return a(n[t])}).join(t)})}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Oo(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=qo(t);return function(r,i){return n(e(r),i,t)}}(t,n):qo(t)});return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=Lo(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=Lo(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")}}}var Yo=Bo(","),Fo=Yo.parse,Io=Yo.parseRows,Ho=Yo.format,jo=Yo.formatBody,Xo=Yo.formatRows,Go=Bo("\t"),Vo=Go.parse,$o=Go.parseRows,Wo=Go.format,Zo=Go.formatBody,Qo=Go.formatRows;function Ko(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function Jo(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function ta(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function na(t,n){return fetch(t,n).then(ta)}function ea(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),na(n,e).then(function(n){return t(n,r)})}}var ra=ea(Fo),ia=ea(Vo);function oa(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.json()}function aa(t){return function(n,e){return na(n,e).then(function(n){return(new DOMParser).parseFromString(n,t)})}}var ua=aa("application/xml"),ca=aa("text/html"),fa=aa("image/svg+xml");function sa(t){return function(){return t}}function la(){return 1e-6*(Math.random()-.5)}function ha(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},v=t._x0,g=t._y0,y=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(v+y)/2))?v=o:y=o,(s=e>=(a=(g+_)/2))?g=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function da(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function pa(t){return t[0]}function va(t){return t[1]}function ga(t,n,e){var r=new ya(null==n?pa:n,null==e?va:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function ya(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function _a(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var ba=ga.prototype=ya.prototype;function ma(t){return t.x+t.vx}function xa(t){return t.y+t.vy}function wa(t){return t.index}function Ma(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Na(t){return t.x}function Aa(t){return t.y}ba.copy=function(){var t,n,e=new ya(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=_a(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=_a(n));return e},ba.add=function(t){var n=+this._x.call(null,t),e=+this._y.call(null,t);return ha(this.cover(n,e),n,e,t)},ba.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)ha(this,a[e],u[e],t[e]);return this},ba.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},ba.data=function(){var t=[];return this.visit(function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)}),t},ba.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},ba.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],v=this._root;for(v&&p.push(new da(v,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(v=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(v.length){var g=(i+a)/2,y=(o+u)/2;p.push(new da(v[3],g,y,a,u),new da(v[2],i,y,g,u),new da(v[1],g,o,a,y),new da(v[0],i,o,g,y)),(f=(n>=y)<<1|t>=g)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,v.data),b=n-+this._y.call(null,v.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=v.data}}return r},ba.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,v=this._y0,g=this._x1,y=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+g)/2))?p=u:g=u,(s=a>=(c=(v+y)/2))?v=c:y=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},ba.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},ba.root=function(){return this._root},ba.size=function(){var t=0;return this.visit(function(n){if(!n.length)do{++t}while(n=n.next)}),t},ba.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new da(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new da(e,f,s,o,a)),(e=c[2])&&u.push(new da(e,r,s,f,a)),(e=c[1])&&u.push(new da(e,f,i,o,s)),(e=c[0])&&u.push(new da(e,r,i,f,s))}return this},ba.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new da(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new da(o,a,u,s,l)),(o=i[1])&&e.push(new da(o,s,u,c,l)),(o=i[2])&&e.push(new da(o,a,l,s,f)),(o=i[3])&&e.push(new da(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},ba.x=function(t){return arguments.length?(this._x=t,this):this._x},ba.y=function(t){return arguments.length?(this._y=t,this):this._y};var Ta=10,Sa=Math.PI*(3-Math.sqrt(5));function ka(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function Ea(t){return(t=ka(Math.abs(t)))?t[1]:NaN}var Ca,Pa=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function za(t){if(!(n=Pa.exec(t)))throw new Error("invalid format: "+t);var n;return new Ra({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Ra(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Da(t,n){var e=ka(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}za.prototype=Ra.prototype,Ra.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var qa={"%":function(t,n){return(100*t).toFixed(n)},b:function(t){return Math.round(t).toString(2)},c:function(t){return t+""},d:function(t){return Math.round(t).toString(10)},e:function(t,n){return t.toExponential(n)},f:function(t,n){return t.toFixed(n)},g:function(t,n){return t.toPrecision(n)},o:function(t){return Math.round(t).toString(8)},p:function(t,n){return Da(100*t,n)},r:Da,s:function(t,n){var e=ka(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Ca=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+ka(t,Math.max(0,n+o-1))[0]},X:function(t){return Math.round(t).toString(16).toUpperCase()},x:function(t){return Math.round(t).toString(16)}};function La(t){return t}var Ua,Oa=Array.prototype.map,Ba=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function Ya(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?La:(n=Oa.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?La:function(t){return function(n){return n.replace(/[0-9]/g,function(n){return t[+n]})}}(Oa.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"-":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=za(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,v=t.comma,g=t.precision,y=t.trim,_=t.type;"n"===_?(v=!0,_="g"):qa[_]||(void 0===g&&(g=12),y=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=qa[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var N=(t=+t)<0;if(t=isNaN(t)?s:x(Math.abs(t),g),y&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(i>0){if(!+t[r])break t;i=0}}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),N&&0==+t&&(N=!1),h=(N?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?Ba[8+Ca/3]:"")+M+(N&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}v&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,T=A<p?new Array(p-A+1).join(n):"";switch(v&&d&&(t=r(T+t,T.length?p-M.length:1/0),T=""),e){case"<":t=h+t+M+T;break;case"=":t=h+T+t+M;break;case"^":t=T.slice(0,A=T.length>>1)+h+t+M+T.slice(A);break;default:t=T+h+t+M}return u(t)}return g=void 0===g?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,g)):Math.max(0,Math.min(20,g)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=za(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Ea(n)/3))),i=Math.pow(10,-r),o=Ba[8+r/3];return function(t){return e(i*t)+o}}}}function Fa(n){return Ua=Ya(n),t.format=Ua.format,t.formatPrefix=Ua.formatPrefix,Ua}function Ia(t){return Math.max(0,-Ea(Math.abs(t)))}function Ha(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Ea(n)/3)))-Ea(Math.abs(t)))}function ja(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Ea(n)-Ea(t))+1}function Xa(){return new Ga}function Ga(){this.reset()}Fa({decimal:".",thousands:",",grouping:[3],currency:["$",""],minus:"-"}),Ga.prototype={constructor:Ga,reset:function(){this.s=this.t=0},add:function(t){$a(Va,t,this.t),$a(this,Va.s,this.s),this.s?this.t+=Va.t:this.s=Va.t},valueOf:function(){return this.s}};var Va=new Ga;function $a(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}var Wa=1e-6,Za=1e-12,Qa=Math.PI,Ka=Qa/2,Ja=Qa/4,tu=2*Qa,nu=180/Qa,eu=Qa/180,ru=Math.abs,iu=Math.atan,ou=Math.atan2,au=Math.cos,uu=Math.ceil,cu=Math.exp,fu=Math.log,su=Math.pow,lu=Math.sin,hu=Math.sign||function(t){return t>0?1:t<0?-1:0},du=Math.sqrt,pu=Math.tan;function vu(t){return t>1?0:t<-1?Qa:Math.acos(t)}function gu(t){return t>1?Ka:t<-1?-Ka:Math.asin(t)}function yu(t){return(t=lu(t/2))*t}function _u(){}function bu(t,n){t&&xu.hasOwnProperty(t.type)&&xu[t.type](t,n)}var mu={Feature:function(t,n){bu(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)bu(e[r].geometry,n)}},xu={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){wu(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)wu(e[r],n,0)},Polygon:function(t,n){Mu(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Mu(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)bu(e[r],n)}};function wu(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Mu(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)wu(t[e],n,1);n.polygonEnd()}function Nu(t,n){t&&mu.hasOwnProperty(t.type)?mu[t.type](t,n):bu(t,n)}var Au,Tu,Su,ku,Eu,Cu=Xa(),Pu=Xa(),zu={point:_u,lineStart:_u,lineEnd:_u,polygonStart:function(){Cu.reset(),zu.lineStart=Ru,zu.lineEnd=Du},polygonEnd:function(){var t=+Cu;Pu.add(t<0?tu+t:t),this.lineStart=this.lineEnd=this.point=_u},sphere:function(){Pu.add(tu)}};function Ru(){zu.point=qu}function Du(){Lu(Au,Tu)}function qu(t,n){zu.point=Lu,Au=t,Tu=n,Su=t*=eu,ku=au(n=(n*=eu)/2+Ja),Eu=lu(n)}function Lu(t,n){var e=(t*=eu)-Su,r=e>=0?1:-1,i=r*e,o=au(n=(n*=eu)/2+Ja),a=lu(n),u=Eu*a,c=ku*o+u*au(i),f=u*r*lu(i);Cu.add(ou(f,c)),Su=t,ku=o,Eu=a}function Uu(t){return[ou(t[1],t[0]),gu(t[2])]}function Ou(t){var n=t[0],e=t[1],r=au(e);return[r*au(n),r*lu(n),lu(e)]}function Bu(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Yu(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function Fu(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function Iu(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function Hu(t){var n=du(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var ju,Xu,Gu,Vu,$u,Wu,Zu,Qu,Ku,Ju,tc,nc,ec,rc,ic,oc,ac,uc,cc,fc,sc,lc,hc,dc,pc,vc,gc=Xa(),yc={point:_c,lineStart:mc,lineEnd:xc,polygonStart:function(){yc.point=wc,yc.lineStart=Mc,yc.lineEnd=Nc,gc.reset(),zu.polygonStart()},polygonEnd:function(){zu.polygonEnd(),yc.point=_c,yc.lineStart=mc,yc.lineEnd=xc,Cu<0?(ju=-(Gu=180),Xu=-(Vu=90)):gc>Wa?Vu=90:gc<-Wa&&(Xu=-90),Ju[0]=ju,Ju[1]=Gu},sphere:function(){ju=-(Gu=180),Xu=-(Vu=90)}};function _c(t,n){Ku.push(Ju=[ju=t,Gu=t]),n<Xu&&(Xu=n),n>Vu&&(Vu=n)}function bc(t,n){var e=Ou([t*eu,n*eu]);if(Qu){var r=Yu(Qu,e),i=Yu([r[1],-r[0],0],r);Hu(i),i=Uu(i);var o,a=t-$u,u=a>0?1:-1,c=i[0]*nu*u,f=ru(a)>180;f^(u*$u<c&&c<u*t)?(o=i[1]*nu)>Vu&&(Vu=o):f^(u*$u<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*nu)<Xu&&(Xu=o):(n<Xu&&(Xu=n),n>Vu&&(Vu=n)),f?t<$u?Ac(ju,t)>Ac(ju,Gu)&&(Gu=t):Ac(t,Gu)>Ac(ju,Gu)&&(ju=t):Gu>=ju?(t<ju&&(ju=t),t>Gu&&(Gu=t)):t>$u?Ac(ju,t)>Ac(ju,Gu)&&(Gu=t):Ac(t,Gu)>Ac(ju,Gu)&&(ju=t)}else Ku.push(Ju=[ju=t,Gu=t]);n<Xu&&(Xu=n),n>Vu&&(Vu=n),Qu=e,$u=t}function mc(){yc.point=bc}function xc(){Ju[0]=ju,Ju[1]=Gu,yc.point=_c,Qu=null}function wc(t,n){if(Qu){var e=t-$u;gc.add(ru(e)>180?e+(e>0?360:-360):e)}else Wu=t,Zu=n;zu.point(t,n),bc(t,n)}function Mc(){zu.lineStart()}function Nc(){wc(Wu,Zu),zu.lineEnd(),ru(gc)>Wa&&(ju=-(Gu=180)),Ju[0]=ju,Ju[1]=Gu,Qu=null}function Ac(t,n){return(n-=t)<0?n+360:n}function Tc(t,n){return t[0]-n[0]}function Sc(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var kc={sphere:_u,point:Ec,lineStart:Pc,lineEnd:Dc,polygonStart:function(){kc.lineStart=qc,kc.lineEnd=Lc},polygonEnd:function(){kc.lineStart=Pc,kc.lineEnd=Dc}};function Ec(t,n){t*=eu;var e=au(n*=eu);Cc(e*au(t),e*lu(t),lu(n))}function Cc(t,n,e){ec+=(t-ec)/++tc,rc+=(n-rc)/tc,ic+=(e-ic)/tc}function Pc(){kc.point=zc}function zc(t,n){t*=eu;var e=au(n*=eu);dc=e*au(t),pc=e*lu(t),vc=lu(n),kc.point=Rc,Cc(dc,pc,vc)}function Rc(t,n){t*=eu;var e=au(n*=eu),r=e*au(t),i=e*lu(t),o=lu(n),a=ou(du((a=pc*o-vc*i)*a+(a=vc*r-dc*o)*a+(a=dc*i-pc*r)*a),dc*r+pc*i+vc*o);nc+=a,oc+=a*(dc+(dc=r)),ac+=a*(pc+(pc=i)),uc+=a*(vc+(vc=o)),Cc(dc,pc,vc)}function Dc(){kc.point=Ec}function qc(){kc.point=Uc}function Lc(){Oc(lc,hc),kc.point=Ec}function Uc(t,n){lc=t,hc=n,t*=eu,n*=eu,kc.point=Oc;var e=au(n);dc=e*au(t),pc=e*lu(t),vc=lu(n),Cc(dc,pc,vc)}function Oc(t,n){t*=eu;var e=au(n*=eu),r=e*au(t),i=e*lu(t),o=lu(n),a=pc*o-vc*i,u=vc*r-dc*o,c=dc*i-pc*r,f=du(a*a+u*u+c*c),s=gu(f),l=f&&-s/f;cc+=l*a,fc+=l*u,sc+=l*c,nc+=s,oc+=s*(dc+(dc=r)),ac+=s*(pc+(pc=i)),uc+=s*(vc+(vc=o)),Cc(dc,pc,vc)}function Bc(t){return function(){return t}}function Yc(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function Fc(t,n){return[ru(t)>Qa?t+Math.round(-t/tu)*tu:t,n]}function Ic(t,n,e){return(t%=tu)?n||e?Yc(jc(t),Xc(n,e)):jc(t):n||e?Xc(n,e):Fc}function Hc(t){return function(n,e){return[(n+=t)>Qa?n-tu:n<-Qa?n+tu:n,e]}}function jc(t){var n=Hc(t);return n.invert=Hc(-t),n}function Xc(t,n){var e=au(t),r=lu(t),i=au(n),o=lu(n);function a(t,n){var a=au(n),u=au(t)*a,c=lu(t)*a,f=lu(n),s=f*e+u*r;return[ou(c*i-s*o,u*e-f*r),gu(s*i+c*o)]}return a.invert=function(t,n){var a=au(n),u=au(t)*a,c=lu(t)*a,f=lu(n),s=f*i-c*o;return[ou(c*i+f*o,u*e+s*r),gu(s*e-u*r)]},a}function Gc(t){function n(n){return(n=t(n[0]*eu,n[1]*eu))[0]*=nu,n[1]*=nu,n}return t=Ic(t[0]*eu,t[1]*eu,t.length>2?t[2]*eu:0),n.invert=function(n){return(n=t.invert(n[0]*eu,n[1]*eu))[0]*=nu,n[1]*=nu,n},n}function Vc(t,n,e,r,i,o){if(e){var a=au(n),u=lu(n),c=r*e;null==i?(i=n+r*tu,o=n-c/2):(i=$c(a,i),o=$c(a,o),(r>0?i<o:i>o)&&(i+=r*tu));for(var f,s=i;r>0?s>o:s<o;s-=c)f=Uu([a,-u*au(s),-u*lu(s)]),t.point(f[0],f[1])}}function $c(t,n){(n=Ou(n))[0]-=t,Hu(n);var e=vu(-n[1]);return((-n[2]<0?-e:e)+tu-Wa)%tu}function Wc(){var t,n=[];return{point:function(n,e){t.push([n,e])},lineStart:function(){n.push(t=[])},lineEnd:_u,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function Zc(t,n){return ru(t[0]-n[0])<Wa&&ru(t[1]-n[1])<Wa}function Qc(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Kc(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach(function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(Zc(r,a)){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);i.lineEnd()}else u.push(e=new Qc(r,t,null,!0)),c.push(e.o=new Qc(r,null,e,!1)),u.push(e=new Qc(a,t,null,!1)),c.push(e.o=new Qc(a,null,e,!0))}}),u.length){for(c.sort(n),Jc(u),Jc(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function Jc(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}Fc.invert=Fc;var tf=Xa();function nf(t){return ru(t[0])<=Qa?t[0]:hu(t[0])*((ru(t[0])+Qa)%tu-Qa)}function ef(t,n){var e=nf(n),r=n[1],i=lu(r),o=[lu(e),-au(e),0],a=0,u=0;tf.reset(),1===i?r=Ka+Wa:-1===i&&(r=-Ka-Wa);for(var c=0,f=t.length;c<f;++c)if(l=(s=t[c]).length)for(var s,l,h=s[l-1],d=nf(h),p=h[1]/2+Ja,v=lu(p),g=au(p),y=0;y<l;++y,d=b,v=x,g=w,h=_){var _=s[y],b=nf(_),m=_[1]/2+Ja,x=lu(m),w=au(m),M=b-d,N=M>=0?1:-1,A=N*M,T=A>Qa,S=v*x;if(tf.add(ou(S*N*lu(A),g*w+S*au(A))),a+=T?M+N*tu:M,T^d>=e^b>=e){var k=Yu(Ou(h),Ou(_));Hu(k);var E=Yu(o,k);Hu(E);var C=(T^M>=0?-1:1)*gu(E[2]);(r>C||r===C&&(k[0]||k[1]))&&(u+=T^M>=0?1:-1)}}return(a<-Wa||a<Wa&&tf<-Wa)^1&u}function rf(t,n,e,r){return function(i){var o,a,u,c=n(i),f=Wc(),s=n(f),l=!1,h={point:d,lineStart:v,lineEnd:g,polygonStart:function(){h.point=y,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=v,h.lineEnd=g,a=T(a);var t=ef(o,r);a.length?(l||(i.polygonStart(),l=!0),Kc(a,af,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function v(){h.point=p,c.lineStart()}function g(){h.point=d,c.lineEnd()}function y(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){y(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(of))}return h}}function of(t){return t.length>1}function af(t,n){return((t=t.x)[0]<0?t[1]-Ka-Wa:Ka-t[1])-((n=n.x)[0]<0?n[1]-Ka-Wa:Ka-n[1])}var uf=rf(function(){return!0},function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?Qa:-Qa,c=ru(o-e);ru(c-Qa)<Wa?(t.point(e,r=(r+a)/2>0?Ka:-Ka),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=Qa&&(ru(e-i)<Wa&&(e-=i*Wa),ru(o-u)<Wa&&(o-=u*Wa),r=function(t,n,e,r){var i,o,a=lu(t-e);return ru(a)>Wa?iu((lu(n)*(o=au(r))*lu(e)-lu(r)*(i=au(n))*lu(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}},function(t,n,e,r){var i;if(null==t)i=e*Ka,r.point(-Qa,i),r.point(0,i),r.point(Qa,i),r.point(Qa,0),r.point(Qa,-i),r.point(0,-i),r.point(-Qa,-i),r.point(-Qa,0),r.point(-Qa,i);else if(ru(t[0]-n[0])>Wa){var o=t[0]<n[0]?Qa:-Qa;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])},[-Qa,-Ka]);function cf(t){var n=au(t),e=6*eu,r=n>0,i=ru(n)>Wa;function o(t,e){return au(t)*au(e)>n}function a(t,e,r){var i=[1,0,0],o=Yu(Ou(t),Ou(e)),a=Bu(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=Yu(i,o),h=Iu(i,f);Fu(h,Iu(o,s));var d=l,p=Bu(h,d),v=Bu(d,d),g=p*p-v*(Bu(h,h)-1);if(!(g<0)){var y=du(g),_=Iu(d,(-p-y)/v);if(Fu(_,h),_=Uu(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var N=x-m,A=ru(N-Qa)<Wa;if(!A&&M<w&&(b=w,w=M,M=b),A||N<Wa?A?w+M>0^_[1]<(ru(_[0]-m)<Wa?w:M):w<=_[1]&&_[1]<=M:N>Qa^(m<=_[0]&&_[0]<=x)){var T=Iu(d,(-p+y)/v);return Fu(T,h),[_,Uu(T)]}}}function u(n,e){var i=r?t:Qa-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return rf(o,function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],v=o(l,h),g=r?v?0:u(l,h):v?u(l+(l<0?Qa:-Qa),h):0;if(!n&&(f=c=v)&&t.lineStart(),v!==c&&(!(d=a(n,p))||Zc(n,d)||Zc(p,d))&&(p[0]+=Wa,p[1]+=Wa,v=o(p[0],p[1])),v!==c)s=0,v?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1]),t.lineEnd()),n=d;else if(i&&n&&r^v){var y;g&e||!(y=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(y[0][0],y[0][1]),t.point(y[1][0],y[1][1]),t.lineEnd()):(t.point(y[1][0],y[1][1]),t.lineEnd(),t.lineStart(),t.point(y[0][0],y[0][1])))}!v||n&&Zc(n,p)||t.point(p[0],p[1]),n=p,c=v,e=g},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}},function(n,r,i,o){Vc(o,t,e,i,n,r)},r?[0,-t]:[-Qa,t-Qa])}var ff=1e9,sf=-ff;function lf(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return ru(r[0]-t)<Wa?i>0?0:3:ru(r[0]-e)<Wa?i>0?2:1:ru(r[1]-n)<Wa?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,v,g,y,_,b=a,m=Wc(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);y=!0,g=!1,p=v=NaN},lineEnd:function(){c&&(M(l,h),d&&g&&m.rejoin(),c.push(m.result()));x.point=w,g&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,l=u[c],h=l[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=T(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&Kc(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),y)l=o,h=a,d=u,y=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&g)b.point(o,a);else{var c=[p=Math.max(sf,Math.min(ff,p)),v=Math.max(sf,Math.min(ff,v))],m=[o=Math.max(sf,Math.min(ff,o)),a=Math.max(sf,Math.min(ff,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(g||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,v=a,g=u}return x}}var hf,df,pf,vf=Xa(),gf={sphere:_u,point:_u,lineStart:function(){gf.point=_f,gf.lineEnd=yf},lineEnd:_u,polygonStart:_u,polygonEnd:_u};function yf(){gf.point=gf.lineEnd=_u}function _f(t,n){hf=t*=eu,df=lu(n*=eu),pf=au(n),gf.point=bf}function bf(t,n){t*=eu;var e=lu(n*=eu),r=au(n),i=ru(t-hf),o=au(i),a=r*lu(i),u=pf*e-df*r*o,c=df*e+pf*r*o;vf.add(ou(du(a*a+u*u),c)),hf=t,df=e,pf=r}function mf(t){return vf.reset(),Nu(t,gf),+vf}var xf=[null,null],wf={type:"LineString",coordinates:xf};function Mf(t,n){return xf[0]=t,xf[1]=n,mf(wf)}var Nf={Feature:function(t,n){return Tf(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(Tf(e[r].geometry,n))return!0;return!1}},Af={Sphere:function(){return!0},Point:function(t,n){return Sf(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Sf(e[r],n))return!0;return!1},LineString:function(t,n){return kf(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(kf(e[r],n))return!0;return!1},Polygon:function(t,n){return Ef(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Ef(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(Tf(e[r],n))return!0;return!1}};function Tf(t,n){return!(!t||!Af.hasOwnProperty(t.type))&&Af[t.type](t,n)}function Sf(t,n){return 0===Mf(t,n)}function kf(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=Mf(t[o],n)))return!0;if(o>0&&(i=Mf(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<Za*i)return!0;e=r}return!1}function Ef(t,n){return!!ef(t.map(Cf),Pf(n))}function Cf(t){return(t=t.map(Pf)).pop(),t}function Pf(t){return[t[0]*eu,t[1]*eu]}function zf(t,n,e){var r=g(t,n-Wa,e).concat(n);return function(t){return r.map(function(n){return[t,n]})}}function Rf(t,n,e){var r=g(t,n-Wa,e).concat(n);return function(t){return r.map(function(n){return[n,t]})}}function Df(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,v=360,y=2.5;function _(){return{type:"MultiLineString",coordinates:b()}}function b(){return g(uu(r/p)*p,e,p).map(s).concat(g(uu(u/v)*v,a,v).map(l)).concat(g(uu(n/h)*h,t,h).filter(function(t){return ru(t%p)>Wa}).map(c)).concat(g(uu(o/d)*d,i,d).filter(function(t){return ru(t%v)>Wa}).map(f))}return _.lines=function(){return b().map(function(t){return{type:"LineString",coordinates:t}})},_.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},_.extent=function(t){return arguments.length?_.extentMajor(t).extentMinor(t):_.extentMinor()},_.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),_.precision(y)):[[r,u],[e,a]]},_.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),_.precision(y)):[[n,o],[t,i]]},_.step=function(t){return arguments.length?_.stepMajor(t).stepMinor(t):_.stepMinor()},_.stepMajor=function(t){return arguments.length?(p=+t[0],v=+t[1],_):[p,v]},_.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],_):[h,d]},_.precision=function(h){return arguments.length?(y=+h,c=zf(o,i,90),f=Rf(n,t,y),s=zf(u,a,90),l=Rf(r,e,y),_):y},_.extentMajor([[-180,-90+Wa],[180,90-Wa]]).extentMinor([[-180,-80-Wa],[180,80+Wa]])}function qf(t){return t}var Lf,Uf,Of,Bf,Yf=Xa(),Ff=Xa(),If={point:_u,lineStart:_u,lineEnd:_u,polygonStart:function(){If.lineStart=Hf,If.lineEnd=Gf},polygonEnd:function(){If.lineStart=If.lineEnd=If.point=_u,Yf.add(ru(Ff)),Ff.reset()},result:function(){var t=Yf/2;return Yf.reset(),t}};function Hf(){If.point=jf}function jf(t,n){If.point=Xf,Lf=Of=t,Uf=Bf=n}function Xf(t,n){Ff.add(Bf*t-Of*n),Of=t,Bf=n}function Gf(){Xf(Lf,Uf)}var Vf=1/0,$f=Vf,Wf=-Vf,Zf=Wf,Qf={point:function(t,n){t<Vf&&(Vf=t);t>Wf&&(Wf=t);n<$f&&($f=n);n>Zf&&(Zf=n)},lineStart:_u,lineEnd:_u,polygonStart:_u,polygonEnd:_u,result:function(){var t=[[Vf,$f],[Wf,Zf]];return Wf=Zf=-($f=Vf=1/0),t}};var Kf,Jf,ts,ns,es=0,rs=0,is=0,os=0,as=0,us=0,cs=0,fs=0,ss=0,ls={point:hs,lineStart:ds,lineEnd:gs,polygonStart:function(){ls.lineStart=ys,ls.lineEnd=_s},polygonEnd:function(){ls.point=hs,ls.lineStart=ds,ls.lineEnd=gs},result:function(){var t=ss?[cs/ss,fs/ss]:us?[os/us,as/us]:is?[es/is,rs/is]:[NaN,NaN];return es=rs=is=os=as=us=cs=fs=ss=0,t}};function hs(t,n){es+=t,rs+=n,++is}function ds(){ls.point=ps}function ps(t,n){ls.point=vs,hs(ts=t,ns=n)}function vs(t,n){var e=t-ts,r=n-ns,i=du(e*e+r*r);os+=i*(ts+t)/2,as+=i*(ns+n)/2,us+=i,hs(ts=t,ns=n)}function gs(){ls.point=hs}function ys(){ls.point=bs}function _s(){ms(Kf,Jf)}function bs(t,n){ls.point=ms,hs(Kf=ts=t,Jf=ns=n)}function ms(t,n){var e=t-ts,r=n-ns,i=du(e*e+r*r);os+=i*(ts+t)/2,as+=i*(ns+n)/2,us+=i,cs+=(i=ns*t-ts*n)*(ts+t),fs+=i*(ns+n),ss+=3*i,hs(ts=t,ns=n)}function xs(t){this._context=t}xs.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,tu)}},result:_u};var ws,Ms,Ns,As,Ts,Ss=Xa(),ks={point:_u,lineStart:function(){ks.point=Es},lineEnd:function(){ws&&Cs(Ms,Ns),ks.point=_u},polygonStart:function(){ws=!0},polygonEnd:function(){ws=null},result:function(){var t=+Ss;return Ss.reset(),t}};function Es(t,n){ks.point=Cs,Ms=As=t,Ns=Ts=n}function Cs(t,n){As-=t,Ts-=n,Ss.add(du(As*As+Ts*Ts)),As=t,Ts=n}function Ps(){this._string=[]}function zs(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function Rs(t){return function(n){var e=new Ds;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Ds(){}function qs(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Nu(e,t.stream(Qf)),n(Qf.result()),null!=r&&t.clipExtent(r),t}function Ls(t,n,e){return qs(t,function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])},e)}function Us(t,n,e){return Ls(t,[[0,0],n],e)}function Os(t,n,e){return qs(t,function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])},e)}function Bs(t,n,e){return qs(t,function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])},e)}Ps.prototype={_radius:4.5,_circle:zs(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=zs(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},Ds.prototype={constructor:Ds,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var Ys=16,Fs=au(30*eu);function Is(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,v,g){var y=f-r,_=s-i,b=y*y+_*_;if(b>4*n&&v--){var m=a+h,x=u+d,w=c+p,M=du(m*m+x*x+w*w),N=gu(w/=M),A=ru(ru(w)-1)<Wa||ru(o-l)<Wa?(o+l)/2:ou(x,m),T=t(A,N),S=T[0],k=T[1],E=S-r,C=k-i,P=_*E-y*C;(P*P/b>n||ru((y*E+_*C)/b-.5)>.3||a*h+u*d+c*p<Fs)&&(e(r,i,o,a,u,c,S,k,A,m/=M,x/=M,w,v,g),g.point(S,k),e(S,k,A,m,x,w,f,s,l,h,d,p,v,g))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,v={point:g,lineStart:y,lineEnd:b,polygonStart:function(){n.polygonStart(),v.lineStart=m},polygonEnd:function(){n.polygonEnd(),v.lineStart=y}};function g(e,r){e=t(e,r),n.point(e[0],e[1])}function y(){s=NaN,v.point=_,n.lineStart()}function _(r,i){var o=Ou([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],Ys,n),n.point(s,l)}function b(){v.point=g,n.lineEnd()}function m(){y(),v.point=x,v.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,v.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,Ys,n),v.lineEnd=b,b()}return v}}(t,n):function(t){return Rs({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var Hs=Rs({point:function(t,n){this.stream.point(t*eu,n*eu)}});function js(t,n,e,r){var i=au(r),o=lu(r),a=i*t,u=o*t,c=i/t,f=o/t,s=(o*e-i*n)/t,l=(o*n+i*e)/t;function h(t,r){return[a*t-u*r+n,e-u*t-a*r]}return h.invert=function(t,n){return[c*t-f*n+s,l-f*t-c*n]},h}function Xs(t){return Gs(function(){return t})()}function Gs(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,v=0,g=0,y=0,_=0,b=0,m=null,x=uf,w=null,M=qf,N=.5;function A(t){return c(t[0]*eu,t[1]*eu)}function T(t){return(t=c.invert(t[0],t[1]))&&[t[0]*nu,t[1]*nu]}function S(){var t=js(l,0,0,b).apply(null,n(p,v)),r=(b?js:function(t,n,e){function r(r,i){return[n+t*r,e-t*i]}return r.invert=function(r,i){return[(r-n)/t,(e-i)/t]},r})(l,h-t[0],d-t[1],b);return e=Ic(g,y,_),u=Yc(n,r),c=Yc(e,u),a=Is(u,N),k()}function k(){return f=s=null,A}return A.stream=function(t){return f&&s===t?f:f=Hs(function(t){return Rs({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(x(a(M(s=t)))))},A.preclip=function(t){return arguments.length?(x=t,m=void 0,k()):x},A.postclip=function(t){return arguments.length?(M=t,w=r=i=o=null,k()):M},A.clipAngle=function(t){return arguments.length?(x=+t?cf(m=t*eu):(m=null,uf),k()):m*nu},A.clipExtent=function(t){return arguments.length?(M=null==t?(w=r=i=o=null,qf):lf(w=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),k()):null==w?null:[[w,r],[i,o]]},A.scale=function(t){return arguments.length?(l=+t,S()):l},A.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],S()):[h,d]},A.center=function(t){return arguments.length?(p=t[0]%360*eu,v=t[1]%360*eu,S()):[p*nu,v*nu]},A.rotate=function(t){return arguments.length?(g=t[0]%360*eu,y=t[1]%360*eu,_=t.length>2?t[2]%360*eu:0,S()):[g*nu,y*nu,_*nu]},A.angle=function(t){return arguments.length?(b=t%360*eu,S()):b*nu},A.precision=function(t){return arguments.length?(a=Is(u,N=t*t),k()):du(N)},A.fitExtent=function(t,n){return Ls(A,t,n)},A.fitSize=function(t,n){return Us(A,t,n)},A.fitWidth=function(t,n){return Os(A,t,n)},A.fitHeight=function(t,n){return Bs(A,t,n)},function(){return n=t.apply(this,arguments),A.invert=n.invert&&T,S()}}function Vs(t){var n=0,e=Qa/3,r=Gs(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*eu,e=t[1]*eu):[n*nu,e*nu]},i}function $s(t,n){var e=lu(t),r=(e+lu(n))/2;if(ru(r)<Wa)return function(t){var n=au(t);function e(t,e){return[t*n,lu(e)/n]}return e.invert=function(t,e){return[t/n,gu(e*n)]},e}(t);var i=1+e*(2*r-e),o=du(i)/r;function a(t,n){var e=du(i-2*r*lu(n))/r;return[e*lu(t*=r),o-e*au(t)]}return a.invert=function(t,n){var e=o-n;return[ou(t,ru(e))/r*hu(e),gu((i-(t*t+e*e)*r*r)/(2*r))]},a}function Ws(){return Vs($s).scale(155.424).center([0,33.6442])}function Zs(){return Ws().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function Qs(t){return function(n,e){var r=au(n),i=au(e),o=t(r*i);return[o*i*lu(n),o*lu(e)]}}function Ks(t){return function(n,e){var r=du(n*n+e*e),i=t(r),o=lu(i),a=au(i);return[ou(n*o,r*a),gu(r&&e*o/r)]}}var Js=Qs(function(t){return du(2/(1+t))});Js.invert=Ks(function(t){return 2*gu(t/2)});var tl=Qs(function(t){return(t=vu(t))&&t/lu(t)});function nl(t,n){return[t,fu(pu((Ka+n)/2))]}function el(t){var n,e,r,i=Xs(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=Qa*a(),u=i(Gc(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===nl?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function rl(t){return pu((Ka+t)/2)}function il(t,n){var e=au(t),r=t===n?lu(t):fu(e/au(n))/fu(rl(n)/rl(t)),i=e*su(rl(t),r)/r;if(!r)return nl;function o(t,n){i>0?n<-Ka+Wa&&(n=-Ka+Wa):n>Ka-Wa&&(n=Ka-Wa);var e=i/su(rl(n),r);return[e*lu(r*t),i-e*au(r*t)]}return o.invert=function(t,n){var e=i-n,o=hu(r)*du(t*t+e*e);return[ou(t,ru(e))/r*hu(e),2*iu(su(i/o,1/r))-Ka]},o}function ol(t,n){return[t,n]}function al(t,n){var e=au(t),r=t===n?lu(t):(e-au(n))/(n-t),i=e/r+t;if(ru(r)<Wa)return ol;function o(t,n){var e=i-n,o=r*t;return[e*lu(o),i-e*au(o)]}return o.invert=function(t,n){var e=i-n;return[ou(t,ru(e))/r*hu(e),i-hu(r)*du(t*t+e*e)]},o}tl.invert=Ks(function(t){return t}),nl.invert=function(t,n){return[t,2*iu(cu(n))-Ka]},ol.invert=ol;var ul=1.340264,cl=-.081106,fl=893e-6,sl=.003796,ll=du(3)/2;function hl(t,n){var e=gu(ll*lu(n)),r=e*e,i=r*r*r;return[t*au(e)/(ll*(ul+3*cl*r+i*(7*fl+9*sl*r))),e*(ul+cl*r+i*(fl+sl*r))]}function dl(t,n){var e=au(n),r=au(t)*e;return[e*lu(t)/r,lu(n)/r]}function pl(t,n,e,r){return 1===t&&1===n&&0===e&&0===r?qf:Rs({point:function(i,o){this.stream.point(i*t+e,o*n+r)}})}function vl(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function gl(t,n){return[au(n)*lu(t),lu(n)]}function yl(t,n){var e=au(n),r=1+au(t)*e;return[e*lu(t)/r,lu(n)/r]}function _l(t,n){return[fu(pu((Ka+n)/2)),-t]}function bl(t,n){return t.parent===n.parent?1:2}function ml(t,n){return t+n.x}function xl(t,n){return Math.max(t,n.y)}function wl(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Ml(t,n){var e,r,i,o,a,u=new Sl(t),c=+t.value&&(u.value=t.value),f=[u];for(null==n&&(n=Nl);e=f.pop();)if(c&&(e.value=+e.data.value),(i=n(e.data))&&(a=i.length))for(e.children=new Array(a),o=a-1;o>=0;--o)f.push(r=e.children[o]=new Sl(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Tl)}function Nl(t){return t.children}function Al(t){t.data=t.data.data}function Tl(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Sl(t){this.data=t,this.depth=this.height=0,this.parent=null}hl.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(ul+cl*i+o*(fl+sl*i))-n)/(ul+3*cl*i+o*(7*fl+9*sl*i)))*r)*i*i,!(ru(e)<Za));++a);return[ll*t*(ul+3*cl*i+o*(7*fl+9*sl*i))/au(r),gu(lu(r)/ll)]},dl.invert=Ks(iu),vl.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(ru(e)>Wa&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},gl.invert=Ks(gu),yl.invert=Ks(function(t){return 2*iu(t)}),_l.invert=function(t,n){return[-n,2*iu(cu(t))-Ka]},Sl.prototype=Ml.prototype={constructor:Sl,count:function(){return this.eachAfter(wl)},each:function(t){var n,e,r,i,o=this,a=[o];do{for(n=a.reverse(),a=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r])}while(a.length);return this},eachAfter:function(t){for(var n,e,r,i=this,o=[i],a=[];i=o.pop();)if(a.push(i),n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e]);for(;i=a.pop();)t(i);return this},eachBefore:function(t){for(var n,e,r=this,i=[r];r=i.pop();)if(t(r),n=r.children)for(e=n.length-1;e>=0;--e)i.push(n[e]);return this},sum:function(t){return this.eachAfter(function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e})},sort:function(t){return this.eachBefore(function(n){n.children&&n.children.sort(t)})},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;for(t=e.pop(),n=r.pop();t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){var t=[];return this.each(function(n){t.push(n)}),t},leaves:function(){var t=[];return this.eachBefore(function(n){n.children||t.push(n)}),t},links:function(){var t=this,n=[];return t.each(function(e){e!==t&&n.push({source:e.parent,target:e})}),n},copy:function(){return Ml(this).eachBefore(Al)}};var kl=Array.prototype.slice;function El(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(kl.call(t))).length,o=[];r<i;)n=t[r],e&&zl(e,n)?++r:(e=Dl(o=Cl(o,n)),r=0);return e}function Cl(t,n){var e,r;if(Rl(n,t))return[n];for(e=0;e<t.length;++e)if(Pl(n,t[e])&&Rl(ql(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(Pl(ql(t[e],t[r]),n)&&Pl(ql(t[e],n),t[r])&&Pl(ql(t[r],n),t[e])&&Rl(Ll(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function Pl(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function zl(t,n){var e=t.r-n.r+1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Rl(t,n){for(var e=0;e<n.length;++e)if(!zl(t,n[e]))return!1;return!0}function Dl(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return ql(t[0],t[1]);case 3:return Ll(t[0],t[1],t[2])}}function ql(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function Ll(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,v=i-s,g=c-o,y=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*v,w=(p*m-v*b)/(2*x)-r,M=(v*g-p*y)/x,N=(d*b-h*m)/(2*x)-i,A=(h*y-d*g)/x,T=M*M+A*A-1,S=2*(o+w*M+N*A),k=w*w+N*N-o*o,E=-(T?(S+Math.sqrt(S*S-4*T*k))/(2*T):k/S);return{x:r+w+M*E,y:i+N+A*E,r:E}}function Ul(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function Ol(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Bl(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Yl(t){this._=t,this.next=null,this.previous=null}function Fl(t){if(!(i=t.length))return 0;var n,e,r,i,o,a,u,c,f,s,l;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Ul(e,n,r=t[2]),n=new Yl(n),e=new Yl(e),r=new Yl(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(u=3;u<i;++u){Ul(n._,e._,r=t[u]),r=new Yl(r),c=e.next,f=n.previous,s=e._.r,l=n._.r;do{if(s<=l){if(Ol(c._,r._)){e=c,n.next=e,e.previous=n,--u;continue t}s+=c._.r,c=c.next}else{if(Ol(f._,r._)){(n=f).next=e,e.previous=n,--u;continue t}l+=f._.r,f=f.previous}}while(c!==f.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=Bl(n);(r=r.next)!==e;)(a=Bl(r))<o&&(n=r,o=a);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=El(n),u=0;u<i;++u)(n=t[u]).x-=r.x,n.y-=r.y;return r.r}function Il(t){return null==t?null:Hl(t)}function Hl(t){if("function"!=typeof t)throw new Error;return t}function jl(){return 0}function Xl(t){return function(){return t}}function Gl(t){return Math.sqrt(t.value)}function Vl(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function $l(t,n){return function(e){if(r=e.children){var r,i,o,a=r.length,u=t(e)*n||0;if(u)for(i=0;i<a;++i)r[i].r+=u;if(o=Fl(r),u)for(i=0;i<a;++i)r[i].r-=u;e.r=o+u}}}function Wl(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function Zl(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function Ql(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}var Kl="$",Jl={depth:-1},th={};function nh(t){return t.id}function eh(t){return t.parentId}function rh(t,n){return t.parent===n.parent?1:2}function ih(t){var n=t.children;return n?n[0]:t.t}function oh(t){var n=t.children;return n?n[n.length-1]:t.t}function ah(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function uh(t,n,e){return t.a.parent===n.parent?t.a:e}function ch(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function fh(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}ch.prototype=Object.create(Sl.prototype);var sh=(1+Math.sqrt(5))/2;function lh(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,v,g,y=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,g=s*s*(v=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/g,g/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),g=s*s*v,(d=Math.max(h/g,g/l))>p){s-=u;break}p=d}y.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?Ql(a,e,r,i,w?r+=f*s/w:o):fh(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return y}var hh=function t(n){function e(t,e,r,i,o){lh(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(sh);var dh=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?Ql(u,e,r,i,r+=(o-r)*u.value/d):fh(u,e,r,e+=(i-e)*u.value/d,o),d-=u.value}else t._squarify=a=lh(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(sh);function ph(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function vh(t,n){return t[0]-n[0]||t[1]-n[1]}function gh(t){for(var n=t.length,e=[0,1],r=2,i=2;i<n;++i){for(;r>1&&ph(t[e[r-2]],t[e[r-1]],t[i])<=0;)--r;e[r++]=i}return e.slice(0,r)}function yh(){return Math.random()}var _h=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(yh),bh=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(yh),mh=function t(n){function e(){var t=bh.source(n).apply(this,arguments);return function(){return Math.exp(t())}}return e.source=t,e}(yh),xh=function t(n){function e(t){return function(){for(var e=0,r=0;r<t;++r)e+=n();return e}}return e.source=t,e}(yh),wh=function t(n){function e(t){var e=xh.source(n)(t);return function(){return e()/t}}return e.source=t,e}(yh),Mh=function t(n){function e(t){return function(){return-Math.log(1-n())/t}}return e.source=t,e}(yh);function Nh(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function Ah(t,n){switch(arguments.length){case 0:break;case 1:this.interpolator(t);break;default:this.interpolator(n).domain(t)}return this}var Th=Array.prototype,Sh=Th.map,kh=Th.slice,Eh={name:"implicit"};function Ch(){var t=uo(),n=[],e=[],r=Eh;function i(i){var o=i+"",a=t.get(o);if(!a){if(r!==Eh)return r;t.set(o,a=n.push(i))}return e[(a-1)%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=uo();for(var r,o,a=-1,u=e.length;++a<u;)t.has(o=(r=e[a])+"")||t.set(o,n.push(r));return i},i.range=function(t){return arguments.length?(e=kh.call(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return Ch(n,e).unknown(r)},Nh.apply(i,arguments),i}function Ph(){var t,n,e=Ch().unknown(void 0),r=e.domain,i=e.range,o=[0,1],a=!1,u=0,c=0,f=.5;function s(){var e=r().length,s=o[1]<o[0],l=o[s-0],h=o[1-s];t=(h-l)/Math.max(1,e-u+2*c),a&&(t=Math.floor(t)),l+=(h-l-t*(e-u))*f,n=t*(1-u),a&&(l=Math.round(l),n=Math.round(n));var d=g(e).map(function(n){return l+t*n});return i(s?d.reverse():d)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),s()):r()},e.range=function(t){return arguments.length?(o=[+t[0],+t[1]],s()):o.slice()},e.rangeRound=function(t){return o=[+t[0],+t[1]],a=!0,s()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(a=!!t,s()):a},e.padding=function(t){return arguments.length?(u=Math.min(1,c=+t),s()):u},e.paddingInner=function(t){return arguments.length?(u=Math.min(1,t),s()):u},e.paddingOuter=function(t){return arguments.length?(c=+t,s()):c},e.align=function(t){return arguments.length?(f=Math.max(0,Math.min(1,t)),s()):f},e.copy=function(){return Ph(r(),o).round(a).paddingInner(u).paddingOuter(c).align(f)},Nh.apply(s(),arguments)}function zh(t){return+t}var Rh=[0,1];function Dh(t){return t}function qh(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function Lh(t){var n,e=t[0],r=t[t.length-1];return e>r&&(n=e,e=r,r=n),function(t){return Math.max(e,Math.min(r,t))}}function Uh(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=qh(i,r),o=e(a,o)):(r=qh(r,i),o=e(o,a)),function(t){return o(r(t))}}function Oh(t,n,e){var r=Math.min(t.length,n.length)-1,o=new Array(r),a=new Array(r),u=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++u<r;)o[u]=qh(t[u],t[u+1]),a[u]=e(n[u],n[u+1]);return function(n){var e=i(t,n,1,r)-1;return a[e](o[e](n))}}function Bh(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function Yh(){var t,n,e,r,i,o,a=Rh,u=Rh,c=Ne,f=Dh;function s(){return r=Math.min(a.length,u.length)>2?Oh:Uh,i=o=null,l}function l(n){return isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),be)))(e)))},l.domain=function(t){return arguments.length?(a=Sh.call(t,zh),f===Dh||(f=Lh(a)),s()):a.slice()},l.range=function(t){return arguments.length?(u=kh.call(t),s()):u.slice()},l.rangeRound=function(t){return u=kh.call(t),c=Ae,s()},l.clamp=function(t){return arguments.length?(f=t?Lh(a):Dh,l):f!==Dh},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function Fh(t,n){return Yh()(t,n)}function Ih(n,e,r,i){var o,a=w(n,e,r);switch((i=za(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=Ha(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=ja(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=Ia(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function Hh(t){var n=t.domain;return t.ticks=function(t){var e=n();return m(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return Ih(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i=n(),o=0,a=i.length-1,u=i[o],c=i[a];return c<u&&(r=u,u=c,c=r,r=o,o=a,a=r),(r=x(u,c,e))>0?r=x(u=Math.floor(u/r)*r,c=Math.ceil(c/r)*r,e):r<0&&(r=x(u=Math.ceil(u*r)/r,c=Math.floor(c*r)/r,e)),r>0?(i[o]=Math.floor(u/r)*r,i[a]=Math.ceil(c/r)*r,n(i)):r<0&&(i[o]=Math.ceil(u*r)/r,i[a]=Math.floor(c*r)/r,n(i)),t},t}function jh(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function Xh(t){return Math.log(t)}function Gh(t){return Math.exp(t)}function Vh(t){return-Math.log(-t)}function $h(t){return-Math.exp(-t)}function Wh(t){return isFinite(t)?+("1e"+t):t<0?0:t}function Zh(t){return function(n){return-t(-n)}}function Qh(n){var e,r,i=n(Xh,Gh),o=i.domain,a=10;function u(){return e=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}(a),r=function(t){return 10===t?Wh:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}(a),o()[0]<0?(e=Zh(e),r=Zh(r),n(Vh,$h)):n(Xh,Gh),i}return i.base=function(t){return arguments.length?(a=+t,u()):a},i.domain=function(t){return arguments.length?(o(t),u()):o()},i.ticks=function(t){var n,i=o(),u=i[0],c=i[i.length-1];(n=c<u)&&(h=u,u=c,c=h);var f,s,l,h=e(u),d=e(c),p=null==t?10:+t,v=[];if(!(a%1)&&d-h<p){if(h=Math.round(h)-1,d=Math.round(d)+1,u>0){for(;h<d;++h)for(s=1,f=r(h);s<a;++s)if(!((l=f*s)<u)){if(l>c)break;v.push(l)}}else for(;h<d;++h)for(s=a-1,f=r(h);s>=1;--s)if(!((l=f*s)<u)){if(l>c)break;v.push(l)}}else v=m(h,d,Math.min(d-h,p)).map(r);return n?v.reverse():v},i.tickFormat=function(n,o){if(null==o&&(o=10===a?".0e":","),"function"!=typeof o&&(o=t.format(o)),n===1/0)return o;null==n&&(n=10);var u=Math.max(1,a*n/i.ticks().length);return function(t){var n=t/r(Math.round(e(t)));return n*a<a-.5&&(n*=a),n<=u?o(t):""}},i.nice=function(){return o(jh(o(),{floor:function(t){return r(Math.floor(e(t)))},ceil:function(t){return r(Math.ceil(e(t)))}}))},i}function Kh(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function Jh(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function td(t){var n=1,e=t(Kh(n),Jh(n));return e.constant=function(e){return arguments.length?t(Kh(n=+e),Jh(n)):n},Hh(e)}function nd(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function ed(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function rd(t){return t<0?-t*t:t*t}function id(t){var n=t(Dh,Dh),e=1;function r(){return 1===e?t(Dh,Dh):.5===e?t(ed,rd):t(nd(e),nd(1/e))}return n.exponent=function(t){return arguments.length?(e=+t,r()):e},Hh(n)}function od(){var t=id(Yh());return t.copy=function(){return Bh(t,od()).exponent(t.exponent())},Nh.apply(t,arguments),t}var ad=new Date,ud=new Date;function cd(t,n,e,r){function i(n){return t(n=new Date(+n)),n}return i.floor=i,i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return cd(function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)},function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););})},e&&(i.count=function(n,r){return ad.setTime(+n),ud.setTime(+r),t(ad),t(ud),Math.floor(e(ad,ud))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var fd=cd(function(){},function(t,n){t.setTime(+t+n)},function(t,n){return n-t});fd.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?cd(function(n){n.setTime(Math.floor(n/t)*t)},function(n,e){n.setTime(+n+e*t)},function(n,e){return(e-n)/t}):fd:null};var sd=fd.range,ld=6e4,hd=6048e5,dd=cd(function(t){t.setTime(t-t.getMilliseconds())},function(t,n){t.setTime(+t+1e3*n)},function(t,n){return(n-t)/1e3},function(t){return t.getUTCSeconds()}),pd=dd.range,vd=cd(function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds())},function(t,n){t.setTime(+t+n*ld)},function(t,n){return(n-t)/ld},function(t){return t.getMinutes()}),gd=vd.range,yd=cd(function(t){t.setTime(t-t.getMilliseconds()-1e3*t.getSeconds()-t.getMinutes()*ld)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getHours()}),_d=yd.range,bd=cd(function(t){t.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*ld)/864e5},function(t){return t.getDate()-1}),md=bd.range;function xd(t){return cd(function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)},function(t,n){t.setDate(t.getDate()+7*n)},function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*ld)/hd})}var wd=xd(0),Md=xd(1),Nd=xd(2),Ad=xd(3),Td=xd(4),Sd=xd(5),kd=xd(6),Ed=wd.range,Cd=Md.range,Pd=Nd.range,zd=Ad.range,Rd=Td.range,Dd=Sd.range,qd=kd.range,Ld=cd(function(t){t.setDate(1),t.setHours(0,0,0,0)},function(t,n){t.setMonth(t.getMonth()+n)},function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())},function(t){return t.getMonth()}),Ud=Ld.range,Od=cd(function(t){t.setMonth(0,1),t.setHours(0,0,0,0)},function(t,n){t.setFullYear(t.getFullYear()+n)},function(t,n){return n.getFullYear()-t.getFullYear()},function(t){return t.getFullYear()});Od.every=function(t){return isFinite(t=Math.floor(t))&&t>0?cd(function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)},function(n,e){n.setFullYear(n.getFullYear()+e*t)}):null};var Bd=Od.range,Yd=cd(function(t){t.setUTCSeconds(0,0)},function(t,n){t.setTime(+t+n*ld)},function(t,n){return(n-t)/ld},function(t){return t.getUTCMinutes()}),Fd=Yd.range,Id=cd(function(t){t.setUTCMinutes(0,0,0)},function(t,n){t.setTime(+t+36e5*n)},function(t,n){return(n-t)/36e5},function(t){return t.getUTCHours()}),Hd=Id.range,jd=cd(function(t){t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+n)},function(t,n){return(n-t)/864e5},function(t){return t.getUTCDate()-1}),Xd=jd.range;function Gd(t){return cd(function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)},function(t,n){t.setUTCDate(t.getUTCDate()+7*n)},function(t,n){return(n-t)/hd})}var Vd=Gd(0),$d=Gd(1),Wd=Gd(2),Zd=Gd(3),Qd=Gd(4),Kd=Gd(5),Jd=Gd(6),tp=Vd.range,np=$d.range,ep=Wd.range,rp=Zd.range,ip=Qd.range,op=Kd.range,ap=Jd.range,up=cd(function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCMonth(t.getUTCMonth()+n)},function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())},function(t){return t.getUTCMonth()}),cp=up.range,fp=cd(function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)},function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()},function(t){return t.getUTCFullYear()});fp.every=function(t){return isFinite(t=Math.floor(t))&&t>0?cd(function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)},function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)}):null};var sp=fp.range;function lp(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function hp(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function dp(t){return{y:t,m:0,d:1,H:0,M:0,S:0,L:0}}function pp(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=wp(i),s=Mp(i),l=wp(o),h=Mp(o),d=wp(a),p=Mp(a),v=wp(u),g=Mp(u),y=wp(c),_=Mp(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:Hp,e:Hp,f:$p,H:jp,I:Xp,j:Gp,L:Vp,m:Wp,M:Zp,p:function(t){return i[+(t.getHours()>=12)]},Q:Nv,s:Av,S:Qp,u:Kp,U:Jp,V:tv,w:nv,W:ev,x:null,X:null,y:rv,Y:iv,Z:ov,"%":Mv},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:av,e:av,f:lv,H:uv,I:cv,j:fv,L:sv,m:hv,M:dv,p:function(t){return i[+(t.getUTCHours()>=12)]},Q:Nv,s:Av,S:pv,u:vv,U:gv,V:yv,w:_v,W:bv,x:null,X:null,y:mv,Y:xv,Z:wv,"%":Mv},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p[r[0].toLowerCase()],e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h[r[0].toLowerCase()],e+r[0].length):-1},b:function(t,n,e){var r=y.exec(n.slice(e));return r?(t.m=_[r[0].toLowerCase()],e+r[0].length):-1},B:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=g[r[0].toLowerCase()],e+r[0].length):-1},c:function(t,e,r){return N(t,n,e,r)},d:Rp,e:Rp,f:Bp,H:qp,I:qp,j:Dp,L:Op,m:zp,M:Lp,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s[r[0].toLowerCase()],e+r[0].length):-1},Q:Fp,s:Ip,S:Up,u:Ap,U:Tp,V:Sp,w:Np,W:kp,x:function(t,n,r){return N(t,e,n,r)},X:function(t,n,e){return N(t,r,n,e)},y:Cp,Y:Ep,Z:Pp,"%":Yp};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=gp[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=dp(1900);if(N(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("p"in o&&(o.H=o.H%12+12*o.p),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=hp(dp(o.y))).getUTCDay(),r=i>4||0===i?$d.ceil(r):$d(r),r=jd.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=n(dp(o.y))).getDay(),r=i>4||0===i?Md.ceil(r):Md(r),r=bd.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?hp(dp(o.y)).getUTCDay():n(dp(o.y)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,hp(o)):n(o)}}function N(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in gp?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",lp);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t,hp);return n.toString=function(){return t},n}}}var vp,gp={"-":"",_:" ",0:"0"},yp=/^\s*\d+/,_p=/^%/,bp=/[\\^$*+?|[\]().{}]/g;function mp(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function xp(t){return t.replace(bp,"\\$&")}function wp(t){return new RegExp("^(?:"+t.map(xp).join("|")+")","i")}function Mp(t){for(var n={},e=-1,r=t.length;++e<r;)n[t[e].toLowerCase()]=e;return n}function Np(t,n,e){var r=yp.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Ap(t,n,e){var r=yp.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Tp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Sp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function kp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function Ep(t,n,e){var r=yp.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function Cp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function Pp(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function zp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function Rp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function Dp(t,n,e){var r=yp.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function qp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function Lp(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function Up(t,n,e){var r=yp.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function Op(t,n,e){var r=yp.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function Bp(t,n,e){var r=yp.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function Yp(t,n,e){var r=_p.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function Fp(t,n,e){var r=yp.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function Ip(t,n,e){var r=yp.exec(n.slice(e));return r?(t.Q=1e3*+r[0],e+r[0].length):-1}function Hp(t,n){return mp(t.getDate(),n,2)}function jp(t,n){return mp(t.getHours(),n,2)}function Xp(t,n){return mp(t.getHours()%12||12,n,2)}function Gp(t,n){return mp(1+bd.count(Od(t),t),n,3)}function Vp(t,n){return mp(t.getMilliseconds(),n,3)}function $p(t,n){return Vp(t,n)+"000"}function Wp(t,n){return mp(t.getMonth()+1,n,2)}function Zp(t,n){return mp(t.getMinutes(),n,2)}function Qp(t,n){return mp(t.getSeconds(),n,2)}function Kp(t){var n=t.getDay();return 0===n?7:n}function Jp(t,n){return mp(wd.count(Od(t),t),n,2)}function tv(t,n){var e=t.getDay();return t=e>=4||0===e?Td(t):Td.ceil(t),mp(Td.count(Od(t),t)+(4===Od(t).getDay()),n,2)}function nv(t){return t.getDay()}function ev(t,n){return mp(Md.count(Od(t),t),n,2)}function rv(t,n){return mp(t.getFullYear()%100,n,2)}function iv(t,n){return mp(t.getFullYear()%1e4,n,4)}function ov(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+mp(n/60|0,"0",2)+mp(n%60,"0",2)}function av(t,n){return mp(t.getUTCDate(),n,2)}function uv(t,n){return mp(t.getUTCHours(),n,2)}function cv(t,n){return mp(t.getUTCHours()%12||12,n,2)}function fv(t,n){return mp(1+jd.count(fp(t),t),n,3)}function sv(t,n){return mp(t.getUTCMilliseconds(),n,3)}function lv(t,n){return sv(t,n)+"000"}function hv(t,n){return mp(t.getUTCMonth()+1,n,2)}function dv(t,n){return mp(t.getUTCMinutes(),n,2)}function pv(t,n){return mp(t.getUTCSeconds(),n,2)}function vv(t){var n=t.getUTCDay();return 0===n?7:n}function gv(t,n){return mp(Vd.count(fp(t),t),n,2)}function yv(t,n){var e=t.getUTCDay();return t=e>=4||0===e?Qd(t):Qd.ceil(t),mp(Qd.count(fp(t),t)+(4===fp(t).getUTCDay()),n,2)}function _v(t){return t.getUTCDay()}function bv(t,n){return mp($d.count(fp(t),t),n,2)}function mv(t,n){return mp(t.getUTCFullYear()%100,n,2)}function xv(t,n){return mp(t.getUTCFullYear()%1e4,n,4)}function wv(){return"+0000"}function Mv(){return"%"}function Nv(t){return+t}function Av(t){return Math.floor(+t/1e3)}function Tv(n){return vp=pp(n),t.timeFormat=vp.format,t.timeParse=vp.parse,t.utcFormat=vp.utcFormat,t.utcParse=vp.utcParse,vp}Tv({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var Sv=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");var kv=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"),Ev=1e3,Cv=60*Ev,Pv=60*Cv,zv=24*Pv,Rv=7*zv,Dv=30*zv,qv=365*zv;function Lv(t){return new Date(t)}function Uv(t){return t instanceof Date?+t:+new Date(+t)}function Ov(t,n,r,i,o,a,u,c,f){var s=Fh(Dh,Dh),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),v=f("%I:%M"),g=f("%I %p"),y=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y"),x=[[u,1,Ev],[u,5,5*Ev],[u,15,15*Ev],[u,30,30*Ev],[a,1,Cv],[a,5,5*Cv],[a,15,15*Cv],[a,30,30*Cv],[o,1,Pv],[o,3,3*Pv],[o,6,6*Pv],[o,12,12*Pv],[i,1,zv],[i,2,2*zv],[r,1,Rv],[n,1,Dv],[n,3,3*Dv],[t,1,qv]];function M(e){return(u(e)<e?d:a(e)<e?p:o(e)<e?v:i(e)<e?g:n(e)<e?r(e)<e?y:_:t(e)<e?b:m)(e)}function N(n,r,i,o){if(null==n&&(n=10),"number"==typeof n){var a=Math.abs(i-r)/n,u=e(function(t){return t[2]}).right(x,a);u===x.length?(o=w(r/qv,i/qv,n),n=t):u?(o=(u=x[a/x[u-1][2]<x[u][2]/a?u-1:u])[1],n=u[0]):(o=Math.max(w(r,i,n),1),n=c)}return null==o?n:n.every(o)}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(Sh.call(t,Uv)):h().map(Lv)},s.ticks=function(t,n){var e,r=h(),i=r[0],o=r[r.length-1],a=o<i;return a&&(e=i,i=o,o=e),e=(e=N(t,i,o,n))?e.range(i,o+1):[],a?e.reverse():e},s.tickFormat=function(t,n){return null==n?M:f(n)},s.nice=function(t,n){var e=h();return(t=N(t,e[0],e[e.length-1],n))?h(jh(e,t)):s},s.copy=function(){return Bh(s,Ov(t,n,r,i,o,a,u,c,f))},s}function Bv(){var t,n,e,r,i,o=0,a=1,u=Dh,c=!1;function f(n){return isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}return f.domain=function(i){return arguments.length?(t=r(o=+i[0]),n=r(a=+i[1]),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function Yv(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function Fv(){var t=id(Bv());return t.copy=function(){return Yv(t,Fv()).exponent(t.exponent())},Ah.apply(t,arguments)}function Iv(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=Dh,l=!1;function h(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(t<n?r:i),s(l?Math.max(0,Math.min(1,t)):t))}return h.domain=function(a){return arguments.length?(t=o(u=+a[0]),n=o(c=+a[1]),e=o(f=+a[2]),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),h):[u,c,f]},h.clamp=function(t){return arguments.length?(l=!!t,h):l},h.interpolator=function(t){return arguments.length?(s=t,h):s},h.unknown=function(t){return arguments.length?(a=t,h):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),h}}function Hv(){var t=id(Iv());return t.copy=function(){return Yv(t,Hv()).exponent(t.exponent())},Ah.apply(t,arguments)}function jv(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var Xv=jv("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Gv=jv("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),Vv=jv("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),$v=jv("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),Wv=jv("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),Zv=jv("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),Qv=jv("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),Kv=jv("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),Jv=jv("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),tg=jv("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab");function ng(t){return ve(t[t.length-1])}var eg=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(jv),rg=ng(eg),ig=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(jv),og=ng(ig),ag=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(jv),ug=ng(ag),cg=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(jv),fg=ng(cg),sg=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(jv),lg=ng(sg),hg=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(jv),dg=ng(hg),pg=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(jv),vg=ng(pg),gg=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(jv),yg=ng(gg),_g=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(jv),bg=ng(_g),mg=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(jv),xg=ng(mg),wg=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(jv),Mg=ng(wg),Ng=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(jv),Ag=ng(Ng),Tg=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(jv),Sg=ng(Tg),kg=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(jv),Eg=ng(kg),Cg=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(jv),Pg=ng(Cg),zg=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(jv),Rg=ng(zg),Dg=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(jv),qg=ng(Dg),Lg=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(jv),Ug=ng(Lg),Og=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(jv),Bg=ng(Og),Yg=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(jv),Fg=ng(Yg),Ig=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(jv),Hg=ng(Ig),jg=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(jv),Xg=ng(jg),Gg=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(jv),Vg=ng(Gg),$g=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(jv),Wg=ng($g),Zg=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(jv),Qg=ng(Zg),Kg=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(jv),Jg=ng(Kg),ty=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(jv),ny=ng(ty);var ey=Ze(re(300,.5,0),re(-240,.5,1)),ry=Ze(re(-100,.75,.35),re(80,1.5,.8)),iy=Ze(re(260,.75,.35),re(80,1.5,.8)),oy=re();var ay=bn(),uy=Math.PI/3,cy=2*Math.PI/3;function fy(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var sy=fy(jv("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),ly=fy(jv("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),hy=fy(jv("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),dy=fy(jv("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function py(t){return function(){return t}}var vy=Math.abs,gy=Math.atan2,yy=Math.cos,_y=Math.max,by=Math.min,my=Math.sin,xy=Math.sqrt,wy=1e-12,My=Math.PI,Ny=My/2,Ay=2*My;function Ty(t){return t>=1?Ny:t<=-1?-Ny:Math.asin(t)}function Sy(t){return t.innerRadius}function ky(t){return t.outerRadius}function Ey(t){return t.startAngle}function Cy(t){return t.endAngle}function Py(t){return t&&t.padAngle}function zy(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/xy(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,v=r+l,g=(h+p)/2,y=(d+v)/2,_=p-h,b=v-d,m=_*_+b*b,x=i-o,w=h*v-p*d,M=(b<0?-1:1)*xy(_y(0,x*x*m-w*w)),N=(w*b-_*M)/m,A=(-w*_-b*M)/m,T=(w*b+_*M)/m,S=(-w*_+b*M)/m,k=N-g,E=A-y,C=T-g,P=S-y;return k*k+E*E>C*C+P*P&&(N=T,A=S),{cx:N,cy:A,x01:-s,y01:-l,x11:N*(i/x-1),y11:A*(i/x-1)}}function Ry(t){this._context=t}function Dy(t){return new Ry(t)}function qy(t){return t[0]}function Ly(t){return t[1]}function Uy(){var t=qy,n=Ly,e=py(!0),r=null,i=Dy,o=null;function a(a){var u,c,f,s=a.length,l=!1;for(null==r&&(o=i(f=to())),u=0;u<=s;++u)!(u<s&&e(c=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(c,u,a),+n(c,u,a));if(f)return o=null,f+""||null}return a.x=function(n){return arguments.length?(t="function"==typeof n?n:py(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:py(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:py(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function Oy(){var t=qy,n=null,e=py(0),r=Ly,i=py(!0),o=null,a=Dy,u=null;function c(c){var f,s,l,h,d,p=c.length,v=!1,g=new Array(p),y=new Array(p);for(null==o&&(u=a(d=to())),f=0;f<=p;++f){if(!(f<p&&i(h=c[f],f,c))===v)if(v=!v)s=f,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=f-1;l>=s;--l)u.point(g[l],y[l]);u.lineEnd(),u.areaEnd()}v&&(g[f]=+t(h,f,c),y[f]=+e(h,f,c),u.point(n?+n(h,f,c):g[f],r?+r(h,f,c):y[f]))}if(d)return u=null,d+""||null}function f(){return Uy().defined(i).curve(a).context(o)}return c.x=function(e){return arguments.length?(t="function"==typeof e?e:py(+e),n=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:py(+n),c):t},c.x1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:py(+t),c):n},c.y=function(t){return arguments.length?(e="function"==typeof t?t:py(+t),r=null,c):e},c.y0=function(t){return arguments.length?(e="function"==typeof t?t:py(+t),c):e},c.y1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:py(+t),c):r},c.lineX0=c.lineY0=function(){return f().x(t).y(e)},c.lineY1=function(){return f().x(t).y(r)},c.lineX1=function(){return f().x(n).y(e)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:py(!!t),c):i},c.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),c):a},c.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),c):o},c}function By(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Yy(t){return t}Ry.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Fy=Hy(Dy);function Iy(t){this._curve=t}function Hy(t){function n(n){return new Iy(t(n))}return n._curve=t,n}function jy(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Hy(t)):n()._curve},t}function Xy(){return jy(Uy().curve(Fy))}function Gy(){var t=Oy().curve(Fy),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return jy(e())},delete t.lineX0,t.lineEndAngle=function(){return jy(r())},delete t.lineX1,t.lineInnerRadius=function(){return jy(i())},delete t.lineY0,t.lineOuterRadius=function(){return jy(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Hy(t)):n()._curve},t}function Vy(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}Iy.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var $y=Array.prototype.slice;function Wy(t){return t.source}function Zy(t){return t.target}function Qy(t){var n=Wy,e=Zy,r=qy,i=Ly,o=null;function a(){var a,u=$y.call(arguments),c=n.apply(this,u),f=e.apply(this,u);if(o||(o=a=to()),t(o,+r.apply(this,(u[0]=c,u)),+i.apply(this,u),+r.apply(this,(u[0]=f,u)),+i.apply(this,u)),a)return o=null,a+""||null}return a.source=function(t){return arguments.length?(n=t,a):n},a.target=function(t){return arguments.length?(e=t,a):e},a.x=function(t){return arguments.length?(r="function"==typeof t?t:py(+t),a):r},a.y=function(t){return arguments.length?(i="function"==typeof t?t:py(+t),a):i},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a}function Ky(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Jy(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function t_(t,n,e,r,i){var o=Vy(n,e),a=Vy(n,e=(e+i)/2),u=Vy(r,e),c=Vy(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(a[0],a[1],u[0],u[1],c[0],c[1])}var n_={draw:function(t,n){var e=Math.sqrt(n/My);t.moveTo(e,0),t.arc(0,0,e,0,Ay)}},e_={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},r_=Math.sqrt(1/3),i_=2*r_,o_={draw:function(t,n){var e=Math.sqrt(n/i_),r=e*r_;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},a_=Math.sin(My/10)/Math.sin(7*My/10),u_=Math.sin(Ay/10)*a_,c_=-Math.cos(Ay/10)*a_,f_={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=u_*e,i=c_*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var a=Ay*o/5,u=Math.cos(a),c=Math.sin(a);t.lineTo(c*e,-u*e),t.lineTo(u*r-c*i,c*r+u*i)}t.closePath()}},s_={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},l_=Math.sqrt(3),h_={draw:function(t,n){var e=-Math.sqrt(n/(3*l_));t.moveTo(0,2*e),t.lineTo(-l_*e,-e),t.lineTo(l_*e,-e),t.closePath()}},d_=Math.sqrt(3)/2,p_=1/Math.sqrt(12),v_=3*(p_/2+1),g_={draw:function(t,n){var e=Math.sqrt(n/v_),r=e/2,i=e*p_,o=r,a=e*p_+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(-.5*r-d_*i,d_*r+-.5*i),t.lineTo(-.5*o-d_*a,d_*o+-.5*a),t.lineTo(-.5*u-d_*c,d_*u+-.5*c),t.lineTo(-.5*r+d_*i,-.5*i-d_*r),t.lineTo(-.5*o+d_*a,-.5*a-d_*o),t.lineTo(-.5*u+d_*c,-.5*c-d_*u),t.closePath()}},y_=[n_,e_,o_,s_,f_,h_,g_];function __(){}function b_(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function m_(t){this._context=t}function x_(t){this._context=t}function w_(t){this._context=t}function M_(t,n){this._basis=new m_(t),this._beta=n}m_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:b_(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:b_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},x_.prototype={areaStart:__,areaEnd:__,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:b_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},w_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:b_(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},M_.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var N_=function t(n){function e(t){return 1===n?new m_(t):new M_(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function A_(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function T_(t,n){this._context=t,this._k=(1-n)/6}T_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:A_(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:A_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var S_=function t(n){function e(t){return new T_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function k_(t,n){this._context=t,this._k=(1-n)/6}k_.prototype={areaStart:__,areaEnd:__,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:A_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var E_=function t(n){function e(t){return new k_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function C_(t,n){this._context=t,this._k=(1-n)/6}C_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:A_(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var P_=function t(n){function e(t){return new C_(t,n)}return e.tension=function(n){return t(+n)},e}(0);function z_(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>wy){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>wy){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function R_(t,n){this._context=t,this._alpha=n}R_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:z_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var D_=function t(n){function e(t){return n?new R_(t,n):new T_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function q_(t,n){this._context=t,this._alpha=n}q_.prototype={areaStart:__,areaEnd:__,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:z_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var L_=function t(n){function e(t){return n?new q_(t,n):new k_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function U_(t,n){this._context=t,this._alpha=n}U_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:z_(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var O_=function t(n){function e(t){return n?new U_(t,n):new C_(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function B_(t){this._context=t}function Y_(t){return t<0?-1:1}function F_(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(Y_(o)+Y_(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function I_(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function H_(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function j_(t){this._context=t}function X_(t){this._context=new G_(t)}function G_(t){this._context=t}function V_(t){this._context=t}function $_(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function W_(t,n){this._context=t,this._t=n}function Z_(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function Q_(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function K_(t,n){return t[n]}function J_(t){var n=t.map(tb);return Q_(t).sort(function(t,e){return n[t]-n[e]})}function tb(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function nb(t){var n=t.map(eb);return Q_(t).sort(function(t,e){return n[t]-n[e]})}function eb(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}function rb(t){return function(){return t}}function ib(t){return t[0]}function ob(t){return t[1]}function ab(){this._=null}function ub(t){t.U=t.C=t.L=t.R=t.P=t.N=null}function cb(t,n){var e=n,r=n.R,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function fb(t,n){var e=n,r=n.L,i=e.U;i?i.L===e?i.L=r:i.R=r:t._=r,r.U=i,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function sb(t){for(;t.L;)t=t.L;return t}function lb(t,n,e,r){var i=[null,null],o=qb.push(i)-1;return i.left=t,i.right=n,e&&db(i,t,n,e),r&&db(i,n,t,r),Rb[t.index].halfedges.push(o),Rb[n.index].halfedges.push(o),i}function hb(t,n,e){var r=[n,e];return r.left=t,r}function db(t,n,e,r){t[0]||t[1]?t.left===e?t[1]=r:t[0]=r:(t[0]=r,t.left=n,t.right=e)}function pb(t,n,e,r,i){var o,a=t[0],u=t[1],c=a[0],f=a[1],s=0,l=1,h=u[0]-c,d=u[1]-f;if(o=n-c,h||!(o>0)){if(o/=h,h<0){if(o<s)return;o<l&&(l=o)}else if(h>0){if(o>l)return;o>s&&(s=o)}if(o=r-c,h||!(o<0)){if(o/=h,h<0){if(o>l)return;o>s&&(s=o)}else if(h>0){if(o<s)return;o<l&&(l=o)}if(o=e-f,d||!(o>0)){if(o/=d,d<0){if(o<s)return;o<l&&(l=o)}else if(d>0){if(o>l)return;o>s&&(s=o)}if(o=i-f,d||!(o<0)){if(o/=d,d<0){if(o>l)return;o>s&&(s=o)}else if(d>0){if(o<s)return;o<l&&(l=o)}return!(s>0||l<1)||(s>0&&(t[0]=[c+s*h,f+s*d]),l<1&&(t[1]=[c+l*h,f+l*d]),!0)}}}}}function vb(t,n,e,r,i){var o=t[1];if(o)return!0;var a,u,c=t[0],f=t.left,s=t.right,l=f[0],h=f[1],d=s[0],p=s[1],v=(l+d)/2,g=(h+p)/2;if(p===h){if(v<n||v>=r)return;if(l>d){if(c){if(c[1]>=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]<e)return}else c=[v,i];o=[v,e]}}else if(u=g-(a=(l-d)/(p-h))*v,a<-1||a>1)if(l>d){if(c){if(c[1]>=i)return}else c=[(e-u)/a,e];o=[(i-u)/a,i]}else{if(c){if(c[1]<e)return}else c=[(i-u)/a,i];o=[(e-u)/a,e]}else if(h<p){if(c){if(c[0]>=r)return}else c=[n,a*n+u];o=[r,a*r+u]}else{if(c){if(c[0]<n)return}else c=[r,a*r+u];o=[n,a*n+u]}return t[0]=c,t[1]=o,!0}function gb(t,n){var e=t.site,r=n.left,i=n.right;return e===i&&(i=r,r=e),i?Math.atan2(i[1]-r[1],i[0]-r[0]):(e===r?(r=n[1],i=n[0]):(r=n[0],i=n[1]),Math.atan2(r[0]-i[0],i[1]-r[1]))}function yb(t,n){return n[+(n.left!==t.site)]}function _b(t,n){return n[+(n.left===t.site)]}B_.prototype={areaStart:__,areaEnd:__,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},j_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:H_(this,this._t0,I_(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,H_(this,I_(this,e=F_(this,t,n)),e);break;default:H_(this,this._t0,e=F_(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(X_.prototype=Object.create(j_.prototype)).point=function(t,n){j_.prototype.point.call(this,n,t)},G_.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},V_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=$_(t),i=$_(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},W_.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}},ab.prototype={constructor:ab,insert:function(t,n){var e,r,i;if(t){if(n.P=t,n.N=t.N,t.N&&(t.N.P=n),t.N=n,t.R){for(t=t.R;t.L;)t=t.L;t.L=n}else t.R=n;e=t}else this._?(t=sb(this._),n.P=null,n.N=t,t.P=t.L=n,e=t):(n.P=n.N=null,this._=n,e=null);for(n.L=n.R=null,n.U=e,n.C=!0,t=n;e&&e.C;)e===(r=e.U).L?(i=r.R)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.R&&(cb(this,e),e=(t=e).U),e.C=!1,r.C=!0,fb(this,r)):(i=r.L)&&i.C?(e.C=i.C=!1,r.C=!0,t=r):(t===e.L&&(fb(this,e),e=(t=e).U),e.C=!1,r.C=!0,cb(this,r)),e=t.U;this._.C=!1},remove:function(t){t.N&&(t.N.P=t.P),t.P&&(t.P.N=t.N),t.N=t.P=null;var n,e,r,i=t.U,o=t.L,a=t.R;if(e=o?a?sb(a):o:a,i?i.L===t?i.L=e:i.R=e:this._=e,o&&a?(r=e.C,e.C=t.C,e.L=o,o.U=e,e!==a?(i=e.U,e.U=t.U,t=e.R,i.L=t,e.R=a,a.U=e):(e.U=i,i=e,t=e.R)):(r=t.C,t=e),t&&(t.U=i),!r)if(t&&t.C)t.C=!1;else{do{if(t===this._)break;if(t===i.L){if((n=i.R).C&&(n.C=!1,i.C=!0,cb(this,i),n=i.R),n.L&&n.L.C||n.R&&n.R.C){n.R&&n.R.C||(n.L.C=!1,n.C=!0,fb(this,n),n=i.R),n.C=i.C,i.C=n.R.C=!1,cb(this,i),t=this._;break}}else if((n=i.L).C&&(n.C=!1,i.C=!0,fb(this,i),n=i.L),n.L&&n.L.C||n.R&&n.R.C){n.L&&n.L.C||(n.R.C=!1,n.C=!0,cb(this,n),n=i.L),n.C=i.C,i.C=n.L.C=!1,fb(this,i),t=this._;break}n.C=!0,t=i,i=i.U}while(!t.C);t&&(t.C=!1)}}};var bb,mb=[];function xb(){ub(this),this.x=this.y=this.arc=this.site=this.cy=null}function wb(t){var n=t.P,e=t.N;if(n&&e){var r=n.site,i=t.site,o=e.site;if(r!==o){var a=i[0],u=i[1],c=r[0]-a,f=r[1]-u,s=o[0]-a,l=o[1]-u,h=2*(c*l-f*s);if(!(h>=-Ub)){var d=c*c+f*f,p=s*s+l*l,v=(l*d-f*p)/h,g=(c*p-s*d)/h,y=mb.pop()||new xb;y.arc=t,y.site=i,y.x=v+a,y.y=(y.cy=g+u)+Math.sqrt(v*v+g*g),t.circle=y;for(var _=null,b=Db._;b;)if(y.y<b.y||y.y===b.y&&y.x<=b.x){if(!b.L){_=b.P;break}b=b.L}else{if(!b.R){_=b;break}b=b.R}Db.insert(_,y),_||(bb=y)}}}}function Mb(t){var n=t.circle;n&&(n.P||(bb=n.N),Db.remove(n),mb.push(n),ub(n),t.circle=null)}var Nb=[];function Ab(){ub(this),this.edge=this.site=this.circle=null}function Tb(t){var n=Nb.pop()||new Ab;return n.site=t,n}function Sb(t){Mb(t),zb.remove(t),Nb.push(t),ub(t)}function kb(t){var n=t.circle,e=n.x,r=n.cy,i=[e,r],o=t.P,a=t.N,u=[t];Sb(t);for(var c=o;c.circle&&Math.abs(e-c.circle.x)<Lb&&Math.abs(r-c.circle.cy)<Lb;)o=c.P,u.unshift(c),Sb(c),c=o;u.unshift(c),Mb(c);for(var f=a;f.circle&&Math.abs(e-f.circle.x)<Lb&&Math.abs(r-f.circle.cy)<Lb;)a=f.N,u.push(f),Sb(f),f=a;u.push(f),Mb(f);var s,l=u.length;for(s=1;s<l;++s)f=u[s],c=u[s-1],db(f.edge,c.site,f.site,i);c=u[0],(f=u[l-1]).edge=lb(c.site,f.site,null,i),wb(c),wb(f)}function Eb(t){for(var n,e,r,i,o=t[0],a=t[1],u=zb._;u;)if((r=Cb(u,a)-o)>Lb)u=u.L;else{if(!((i=o-Pb(u,a))>Lb)){r>-Lb?(n=u.P,e=u):i>-Lb?(n=u,e=u.N):n=e=u;break}if(!u.R){n=u;break}u=u.R}!function(t){Rb[t.index]={site:t,halfedges:[]}}(t);var c=Tb(t);if(zb.insert(n,c),n||e){if(n===e)return Mb(n),e=Tb(n.site),zb.insert(c,e),c.edge=e.edge=lb(n.site,c.site),wb(n),void wb(e);if(e){Mb(n),Mb(e);var f=n.site,s=f[0],l=f[1],h=t[0]-s,d=t[1]-l,p=e.site,v=p[0]-s,g=p[1]-l,y=2*(h*g-d*v),_=h*h+d*d,b=v*v+g*g,m=[(g*_-d*b)/y+s,(h*b-v*_)/y+l];db(e.edge,f,p,m),c.edge=lb(f,t,null,m),e.edge=lb(t,p,null,m),wb(n),wb(e)}else c.edge=lb(n.site,c.site)}}function Cb(t,n){var e=t.site,r=e[0],i=e[1],o=i-n;if(!o)return r;var a=t.P;if(!a)return-1/0;var u=(e=a.site)[0],c=e[1],f=c-n;if(!f)return u;var s=u-r,l=1/o-1/f,h=s/f;return l?(-h+Math.sqrt(h*h-2*l*(s*s/(-2*f)-c+f/2+i-o/2)))/l+r:(r+u)/2}function Pb(t,n){var e=t.N;if(e)return Cb(e,n);var r=t.site;return r[1]===n?r[0]:1/0}var zb,Rb,Db,qb,Lb=1e-6,Ub=1e-12;function Ob(t,n,e){return(t[0]-e[0])*(n[1]-t[1])-(t[0]-n[0])*(e[1]-t[1])}function Bb(t,n){return n[1]-t[1]||n[0]-t[0]}function Yb(t,n){var e,r,i,o=t.sort(Bb).pop();for(qb=[],Rb=new Array(t.length),zb=new ab,Db=new ab;;)if(i=bb,o&&(!i||o[1]<i.y||o[1]===i.y&&o[0]<i.x))o[0]===e&&o[1]===r||(Eb(o),e=o[0],r=o[1]),o=t.pop();else{if(!i)break;kb(i.arc)}if(function(){for(var t,n,e,r,i=0,o=Rb.length;i<o;++i)if((t=Rb[i])&&(r=(n=t.halfedges).length)){var a=new Array(r),u=new Array(r);for(e=0;e<r;++e)a[e]=e,u[e]=gb(t,qb[n[e]]);for(a.sort(function(t,n){return u[n]-u[t]}),e=0;e<r;++e)u[e]=n[a[e]];for(e=0;e<r;++e)n[e]=u[e]}}(),n){var a=+n[0][0],u=+n[0][1],c=+n[1][0],f=+n[1][1];!function(t,n,e,r){for(var i,o=qb.length;o--;)vb(i=qb[o],t,n,e,r)&&pb(i,t,n,e,r)&&(Math.abs(i[0][0]-i[1][0])>Lb||Math.abs(i[0][1]-i[1][1])>Lb)||delete qb[o]}(a,u,c,f),function(t,n,e,r){var i,o,a,u,c,f,s,l,h,d,p,v,g=Rb.length,y=!0;for(i=0;i<g;++i)if(o=Rb[i]){for(a=o.site,u=(c=o.halfedges).length;u--;)qb[c[u]]||c.splice(u,1);for(u=0,f=c.length;u<f;)p=(d=_b(o,qb[c[u]]))[0],v=d[1],l=(s=yb(o,qb[c[++u%f]]))[0],h=s[1],(Math.abs(p-l)>Lb||Math.abs(v-h)>Lb)&&(c.splice(u,0,qb.push(hb(a,d,Math.abs(p-t)<Lb&&r-v>Lb?[t,Math.abs(l-t)<Lb?h:r]:Math.abs(v-r)<Lb&&e-p>Lb?[Math.abs(h-r)<Lb?l:e,r]:Math.abs(p-e)<Lb&&v-n>Lb?[e,Math.abs(l-e)<Lb?h:n]:Math.abs(v-n)<Lb&&p-t>Lb?[Math.abs(h-n)<Lb?l:t,n]:null))-1),++f);f&&(y=!1)}if(y){var _,b,m,x=1/0;for(i=0,y=null;i<g;++i)(o=Rb[i])&&(m=(_=(a=o.site)[0]-t)*_+(b=a[1]-n)*b)<x&&(x=m,y=o);if(y){var w=[t,n],M=[t,r],N=[e,r],A=[e,n];y.halfedges.push(qb.push(hb(a=y.site,w,M))-1,qb.push(hb(a,M,N))-1,qb.push(hb(a,N,A))-1,qb.push(hb(a,A,w))-1)}}for(i=0;i<g;++i)(o=Rb[i])&&(o.halfedges.length||delete Rb[i])}(a,u,c,f)}this.edges=qb,this.cells=Rb,zb=Db=qb=Rb=null}function Fb(t){return function(){return t}}function Ib(t,n,e){this.target=t,this.type=n,this.transform=e}function Hb(t,n,e){this.k=t,this.x=n,this.y=e}Yb.prototype={constructor:Yb,polygons:function(){var t=this.edges;return this.cells.map(function(n){var e=n.halfedges.map(function(e){return yb(n,t[e])});return e.data=n.site.data,e})},triangles:function(){var t=[],n=this.edges;return this.cells.forEach(function(e,r){if(o=(i=e.halfedges).length)for(var i,o,a,u=e.site,c=-1,f=n[i[o-1]],s=f.left===u?f.right:f.left;++c<o;)a=s,s=(f=n[i[c]]).left===u?f.right:f.left,a&&s&&r<a.index&&r<s.index&&Ob(u,a,s)<0&&t.push([u.data,a.data,s.data])}),t},links:function(){return this.edges.filter(function(t){return t.right}).map(function(t){return{source:t.left.data,target:t.right.data}})},find:function(t,n,e){for(var r,i,o=this,a=o._found||0,u=o.cells.length;!(i=o.cells[a]);)if(++a>=u)return null;var c=t-i.site[0],f=n-i.site[1],s=c*c+f*f;do{i=o.cells[r=a],a=null,i.halfedges.forEach(function(e){var r=o.edges[e],u=r.left;if(u!==i.site&&u||(u=r.right)){var c=t-u[0],f=n-u[1],l=c*c+f*f;l<s&&(s=l,a=u.index)}})}while(null!==a);return o._found=r,null==e||s<=e*e?i.site:null}},Hb.prototype={constructor:Hb,scale:function(t){return 1===t?this:new Hb(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new Hb(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var jb=new Hb(1,0,0);function Xb(t){for(;!t.__zoom;)if(!(t=t.parentNode))return jb;return t.__zoom}function Gb(){t.event.stopImmediatePropagation()}function Vb(){t.event.preventDefault(),t.event.stopImmediatePropagation()}function $b(){return!t.event.ctrlKey&&!t.event.button}function Wb(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function Zb(){return this.__zoom||jb}function Qb(){return-t.event.deltaY*(1===t.event.deltaMode?.05:t.event.deltaMode?1:.002)}function Kb(){return navigator.maxTouchPoints||"ontouchstart"in this}function Jb(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Xb.prototype=Hb.prototype,t.FormatSpecifier=Ra,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>mr&&e.name===n)return new Lr([[t]],gi,n,+r);return null},t.arc=function(){var t=Sy,n=ky,e=py(0),r=null,i=Ey,o=Cy,a=Py,u=null;function c(){var c,f,s=+t.apply(this,arguments),l=+n.apply(this,arguments),h=i.apply(this,arguments)-Ny,d=o.apply(this,arguments)-Ny,p=vy(d-h),v=d>h;if(u||(u=c=to()),l<s&&(f=l,l=s,s=f),l>wy)if(p>Ay-wy)u.moveTo(l*yy(h),l*my(h)),u.arc(0,0,l,h,d,!v),s>wy&&(u.moveTo(s*yy(d),s*my(d)),u.arc(0,0,s,d,h,v));else{var g,y,_=h,b=d,m=h,x=d,w=p,M=p,N=a.apply(this,arguments)/2,A=N>wy&&(r?+r.apply(this,arguments):xy(s*s+l*l)),T=by(vy(l-s)/2,+e.apply(this,arguments)),S=T,k=T;if(A>wy){var E=Ty(A/s*my(N)),C=Ty(A/l*my(N));(w-=2*E)>wy?(m+=E*=v?1:-1,x-=E):(w=0,m=x=(h+d)/2),(M-=2*C)>wy?(_+=C*=v?1:-1,b-=C):(M=0,_=b=(h+d)/2)}var P=l*yy(_),z=l*my(_),R=s*yy(x),D=s*my(x);if(T>wy){var q,L=l*yy(b),U=l*my(b),O=s*yy(m),B=s*my(m);if(p<My&&(q=function(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<wy))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}(P,z,O,B,L,U,R,D))){var Y=P-q[0],F=z-q[1],I=L-q[0],H=U-q[1],j=1/my(function(t){return t>1?0:t<-1?My:Math.acos(t)}((Y*I+F*H)/(xy(Y*Y+F*F)*xy(I*I+H*H)))/2),X=xy(q[0]*q[0]+q[1]*q[1]);S=by(T,(s-X)/(j-1)),k=by(T,(l-X)/(j+1))}}M>wy?k>wy?(g=zy(O,B,P,z,l,k,v),y=zy(L,U,R,D,l,k,v),u.moveTo(g.cx+g.x01,g.cy+g.y01),k<T?u.arc(g.cx,g.cy,k,gy(g.y01,g.x01),gy(y.y01,y.x01),!v):(u.arc(g.cx,g.cy,k,gy(g.y01,g.x01),gy(g.y11,g.x11),!v),u.arc(0,0,l,gy(g.cy+g.y11,g.cx+g.x11),gy(y.cy+y.y11,y.cx+y.x11),!v),u.arc(y.cx,y.cy,k,gy(y.y11,y.x11),gy(y.y01,y.x01),!v))):(u.moveTo(P,z),u.arc(0,0,l,_,b,!v)):u.moveTo(P,z),s>wy&&w>wy?S>wy?(g=zy(R,D,L,U,s,-S,v),y=zy(P,z,O,B,s,-S,v),u.lineTo(g.cx+g.x01,g.cy+g.y01),S<T?u.arc(g.cx,g.cy,S,gy(g.y01,g.x01),gy(y.y01,y.x01),!v):(u.arc(g.cx,g.cy,S,gy(g.y01,g.x01),gy(g.y11,g.x11),!v),u.arc(0,0,s,gy(g.cy+g.y11,g.cx+g.x11),gy(y.cy+y.y11,y.cx+y.x11),v),u.arc(y.cx,y.cy,S,gy(y.y11,y.x11),gy(y.y01,y.x01),!v))):u.arc(0,0,s,x,m,v):u.lineTo(R,D)}else u.moveTo(0,0);if(u.closePath(),c)return u=null,c+""||null}return c.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-My/2;return[yy(r)*e,my(r)*e]},c.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:py(+n),c):t},c.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:py(+t),c):n},c.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:py(+t),c):e},c.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:py(+t),c):r},c.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:py(+t),c):i},c.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:py(+t),c):o},c.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:py(+t),c):a},c.context=function(t){return arguments.length?(u=null==t?null:t,c):u},c},t.area=Oy,t.areaRadial=Gy,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r=t[n].trim();if(r)if("true"===r)r=!0;else if("false"===r)r=!1;else if("NaN"===r)r=NaN;else if(isNaN(e=+r)){if(!/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/.test(r))continue;r=new Date(r)}else r=e;else r=null;t[n]=r}return t},t.axisBottom=function(t){return Y(D,t)},t.axisLeft=function(t){return Y(q,t)},t.axisRight=function(t){return Y(R,t)},t.axisTop=function(t){return Y(z,t)},t.bisect=i,t.bisectLeft=o,t.bisectRight=i,t.bisector=e,t.blob=function(t,n){return fetch(t,n).then(Ko)},t.brush=function(){return Yi(Ei)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return Yi(Si)},t.brushY=function(){return Yi(ki)},t.buffer=function(t,n){return fetch(t,n).then(Jo)},t.chord=function(){var t=0,n=null,e=null,r=null;function i(i){var o,a,u,c,f,s,l=i.length,h=[],d=g(l),p=[],v=[],y=v.groups=new Array(l),_=new Array(l*l);for(o=0,f=-1;++f<l;){for(a=0,s=-1;++s<l;)a+=i[f][s];h.push(a),p.push(g(l)),o+=a}for(n&&d.sort(function(t,e){return n(h[t],h[e])}),e&&p.forEach(function(t,n){t.sort(function(t,r){return e(i[n][t],i[n][r])})}),c=(o=Gi(0,Xi-t*l)/o)?t:Xi/l,a=0,f=-1;++f<l;){for(u=a,s=-1;++s<l;){var b=d[f],m=p[b][s],x=i[b][m],w=a,M=a+=x*o;_[m*l+b]={index:b,subindex:m,startAngle:w,endAngle:M,value:x}}y[b]={index:b,startAngle:u,endAngle:a,value:h[b]},a+=c}for(f=-1;++f<l;)for(s=f-1;++s<l;){var N=_[s*l+f],A=_[f*l+s];(N.value||A.value)&&v.push(N.value<A.value?{source:A,target:N}:{source:N,target:A})}return r?v.sort(r):v}return i.padAngle=function(n){return arguments.length?(t=Gi(0,n),i):t},i.sortGroups=function(t){return arguments.length?(n=t,i):n},i.sortSubgroups=function(t){return arguments.length?(e=t,i):e},i.sortChords=function(t){return arguments.length?(null==t?r=null:(r=Vi(t))._=t,i):r&&r._},i},t.clientPoint=Ot,t.cluster=function(){var t=bl,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter(function(n){var e=n.children;e?(n.x=function(t){return t.reduce(ml,0)/t.length}(e),n.y=function(t){return 1+t.reduce(xl,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)});var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=vn,t.contourDensity=function(){var t=So,n=ko,e=Eo,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=_o(20);function l(r){var i=new Float32Array(c*f),l=new Float32Array(c*f);r.forEach(function(r,o,s){var l=+t(r,o,s)+u>>a,h=+n(r,o,s)+u>>a,d=+e(r,o,s);l>=0&&l<c&&h>=0&&h<f&&(i[l+h*c]+=d)}),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),To({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),To({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),Ao({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),To({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a);var d=s(i);if(!Array.isArray(d)){var p=A(i);d=w(0,p,d),(d=g(0,Math.floor(p/d)*d,d)).shift()}return No().thresholds(d).size([c,f])(i).map(h)}function h(t){return t.value*=Math.pow(2,-2*a),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(v)}function v(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function y(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,l}return l.x=function(n){return arguments.length?(t="function"==typeof n?n:_o(+n),l):t},l.y=function(t){return arguments.length?(n="function"==typeof t?t:_o(+t),l):n},l.weight=function(t){return arguments.length?(e="function"==typeof t?t:_o(+t),l):e},l.size=function(t){if(!arguments.length)return[r,i];var n=Math.ceil(t[0]),e=Math.ceil(t[1]);if(!(n>=0||n>=0))throw new Error("invalid size");return r=n,i=e,y()},l.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),y()},l.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?_o(go.call(t)):_o(t),l):s},l.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},l},t.contours=No,t.create=function(t){return Rt(Z(t).call(document.documentElement))},t.creator=Z,t.cross=function(t,n,e){var r,i,o,u,c=t.length,f=n.length,s=new Array(c*f);for(null==e&&(e=a),r=o=0;r<c;++r)for(u=t[r],i=0;i<f;++i,++o)s[o]=e(u,n[i]);return s},t.csv=ra,t.csvFormat=Ho,t.csvFormatBody=jo,t.csvFormatRows=Xo,t.csvParse=Fo,t.csvParseRows=Io,t.cubehelix=re,t.curveBasis=function(t){return new m_(t)},t.curveBasisClosed=function(t){return new x_(t)},t.curveBasisOpen=function(t){return new w_(t)},t.curveBundle=N_,t.curveCardinal=S_,t.curveCardinalClosed=E_,t.curveCardinalOpen=P_,t.curveCatmullRom=D_,t.curveCatmullRomClosed=L_,t.curveCatmullRomOpen=O_,t.curveLinear=Dy,t.curveLinearClosed=function(t){return new B_(t)},t.curveMonotoneX=function(t){return new j_(t)},t.curveMonotoneY=function(t){return new X_(t)},t.curveNatural=function(t){return new V_(t)},t.curveStep=function(t){return new W_(t,.5)},t.curveStepAfter=function(t){return new W_(t,1)},t.curveStepBefore=function(t){return new W_(t,0)},t.customEvent=kt,t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=f,t.dispatch=I,t.drag=function(){var n,e,r,i,o=Vt,a=$t,u=Wt,c=Zt,f={},s=I("start","drag","end"),l=0,h=0;function d(t){t.on("mousedown.drag",p).filter(c).on("touchstart.drag",y).on("touchmove.drag",_).on("touchend.drag touchcancel.drag",b).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(){if(!i&&o.apply(this,arguments)){var u=m("mouse",a.apply(this,arguments),Bt,this,arguments);u&&(Rt(t.event.view).on("mousemove.drag",v,!0).on("mouseup.drag",g,!0),Ht(t.event.view),Ft(),r=!1,n=t.event.clientX,e=t.event.clientY,u("start"))}}function v(){if(It(),!r){var i=t.event.clientX-n,o=t.event.clientY-e;r=i*i+o*o>h}f.mouse("drag")}function g(){Rt(t.event.view).on("mousemove.drag mouseup.drag",null),jt(t.event.view,r),It(),f.mouse("end")}function y(){if(o.apply(this,arguments)){var n,e,r=t.event.changedTouches,i=a.apply(this,arguments),u=r.length;for(n=0;n<u;++n)(e=m(r[n].identifier,i,Yt,this,arguments))&&(Ft(),e("start"))}}function _(){var n,e,r=t.event.changedTouches,i=r.length;for(n=0;n<i;++n)(e=f[r[n].identifier])&&(It(),e("drag"))}function b(){var n,e,r=t.event.changedTouches,o=r.length;for(i&&clearTimeout(i),i=setTimeout(function(){i=null},500),n=0;n<o;++n)(e=f[r[n].identifier])&&(Ft(),e("end"))}function m(n,e,r,i,o){var a,c,h,p=r(e,n),v=s.copy();if(kt(new Gt(d,"beforestart",a,n,l,p[0],p[1],0,0,v),function(){return null!=(t.event.subject=a=u.apply(i,o))&&(c=a.x-p[0]||0,h=a.y-p[1]||0,!0)}))return function t(u){var s,g=p;switch(u){case"start":f[n]=t,s=l++;break;case"end":delete f[n],--l;case"drag":p=r(e,n),s=l}kt(new Gt(d,u,a,n,s,p[0]+c,p[1]+h,p[0]-g[0],p[1]-g[1],v),v.apply,v,[u,i,o])}}return d.filter=function(t){return arguments.length?(o="function"==typeof t?t:Xt(!!t),d):o},d.container=function(t){return arguments.length?(a="function"==typeof t?t:Xt(t),d):a},d.subject=function(t){return arguments.length?(u="function"==typeof t?t:Xt(t),d):u},d.touchable=function(t){return arguments.length?(c="function"==typeof t?t:Xt(!!t),d):c},d.on=function(){var t=s.on.apply(s,arguments);return t===s?d:t},d.clickDistance=function(t){return arguments.length?(h=(t=+t)*t,d):Math.sqrt(h)},d},t.dragDisable=Ht,t.dragEnable=jt,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Bo(t);return na(n,e).then(function(t){return i.parse(t,r)})},t.dsvFormat=Bo,t.easeBack=fi,t.easeBackIn=ui,t.easeBackInOut=fi,t.easeBackOut=ci,t.easeBounce=ai,t.easeBounceIn=function(t){return 1-ai(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-ai(1-t):ai(t-1)+1)/2},t.easeBounceOut=ai,t.easeCircle=Wr,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=Wr,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=Fr,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=Fr,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=hi,t.easeElasticIn=li,t.easeElasticInOut=di,t.easeElasticOut=hi,t.easeExp=$r,t.easeExpIn=function(t){return Math.pow(2,10*t-10)},t.easeExpInOut=$r,t.easeExpOut=function(t){return 1-Math.pow(2,-10*t)},t.easeLinear=function(t){return+t},t.easePoly=jr,t.easePolyIn=Ir,t.easePolyInOut=jr,t.easePolyOut=Hr,t.easeQuad=Yr,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=Yr,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=Vr,t.easeSinIn=function(t){return 1-Math.cos(t*Gr)},t.easeSinInOut=Vr,t.easeSinOut=function(t){return Math.sin(t*Gr)},t.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},t.extent=s,t.forceCenter=function(t,n){var e;function r(){var r,i,o=e.length,a=0,u=0;for(r=0;r<o;++r)a+=(i=e[r]).x,u+=i.y;for(a=a/o-t,u=u/o-n,r=0;r<o;++r)(i=e[r]).x-=a,i.y-=u}return null==t&&(t=0),null==n&&(n=0),r.initialize=function(t){e=t},r.x=function(n){return arguments.length?(t=+n,r):t},r.y=function(t){return arguments.length?(n=+t,r):n},r},t.forceCollide=function(t){var n,e,r=1,i=1;function o(){for(var t,o,u,c,f,s,l,h=n.length,d=0;d<i;++d)for(o=ga(n,ma,xa).visitAfter(a),t=0;t<h;++t)u=n[t],s=e[u.index],l=s*s,c=u.x+u.vx,f=u.y+u.vy,o.visit(p);function p(t,n,e,i,o){var a=t.data,h=t.r,d=s+h;if(!a)return n>c+d||i<c-d||e>f+d||o<f-d;if(a.index>u.index){var p=c-a.x-a.vx,v=f-a.y-a.vy,g=p*p+v*v;g<d*d&&(0===p&&(g+=(p=la())*p),0===v&&(g+=(v=la())*v),g=(d-(g=Math.sqrt(g)))/g*r,u.vx+=(p*=g)*(d=(h*=h)/(l+h)),u.vy+=(v*=g)*d,a.vx-=p*(d=1-d),a.vy-=v*d)}}}function a(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function u(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=sa(null==t?1:+t)),o.initialize=function(t){n=t,u()},o.iterations=function(t){return arguments.length?(i=+t,o):i},o.strength=function(t){return arguments.length?(r=+t,o):r},o.radius=function(n){return arguments.length?(t="function"==typeof n?n:sa(+n),u(),o):t},o},t.forceLink=function(t){var n,e,r,i,o,a=wa,u=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},c=sa(30),f=1;function s(r){for(var i=0,a=t.length;i<f;++i)for(var u,c,s,l,h,d,p,v=0;v<a;++v)c=(u=t[v]).source,l=(s=u.target).x+s.vx-c.x-c.vx||la(),h=s.y+s.vy-c.y-c.vy||la(),l*=d=((d=Math.sqrt(l*l+h*h))-e[v])/d*r*n[v],h*=d,s.vx-=l*(p=o[v]),s.vy-=h*p,c.vx+=l*(p=1-p),c.vy+=h*p}function l(){if(r){var u,c,f=r.length,s=t.length,l=uo(r,a);for(u=0,i=new Array(f);u<s;++u)(c=t[u]).index=u,"object"!=typeof c.source&&(c.source=Ma(l,c.source)),"object"!=typeof c.target&&(c.target=Ma(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(u=0,o=new Array(s);u<s;++u)c=t[u],o[u]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),h(),e=new Array(s),d()}}function h(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+u(t[e],e,t)}function d(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+c(t[n],n,t)}return null==t&&(t=[]),s.initialize=function(t){r=t,l()},s.links=function(n){return arguments.length?(t=n,l(),s):t},s.id=function(t){return arguments.length?(a=t,s):a},s.iterations=function(t){return arguments.length?(f=+t,s):f},s.strength=function(t){return arguments.length?(u="function"==typeof t?t:sa(+t),h(),s):u},s.distance=function(t){return arguments.length?(c="function"==typeof t?t:sa(+t),d(),s):c},s},t.forceManyBody=function(){var t,n,e,r,i=sa(-30),o=1,a=1/0,u=.81;function c(r){var i,o=t.length,a=ga(t,Na,Aa).visitAfter(s);for(e=r,i=0;i<o;++i)n=t[i],a.visit(l)}function f(){if(t){var n,e,o=t.length;for(r=new Array(o),n=0;n<o;++n)e=t[n],r[e.index]=+i(e,n,t)}}function s(t){var n,e,i,o,a,u=0,c=0;if(t.length){for(i=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,i+=e*n.x,o+=e*n.y);t.x=i/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=r[n.data.index]}while(n=n.next)}t.value=u}function l(t,i,c,f){if(!t.value)return!0;var s=t.x-n.x,l=t.y-n.y,h=f-i,d=s*s+l*l;if(h*h/u<d)return d<a&&(0===s&&(d+=(s=la())*s),0===l&&(d+=(l=la())*l),d<o&&(d=Math.sqrt(o*d)),n.vx+=s*t.value*e/d,n.vy+=l*t.value*e/d),!0;if(!(t.length||d>=a)){(t.data!==n||t.next)&&(0===s&&(d+=(s=la())*s),0===l&&(d+=(l=la())*l),d<o&&(d=Math.sqrt(o*d)));do{t.data!==n&&(h=r[t.data.index]*e/d,n.vx+=s*h,n.vy+=l*h)}while(t=t.next)}}return c.initialize=function(n){t=n,f()},c.strength=function(t){return arguments.length?(i="function"==typeof t?t:sa(+t),f(),c):i},c.distanceMin=function(t){return arguments.length?(o=t*t,c):Math.sqrt(o)},c.distanceMax=function(t){return arguments.length?(a=t*t,c):Math.sqrt(a)},c.theta=function(t){return arguments.length?(u=t*t,c):Math.sqrt(u)},c},t.forceRadial=function(t,n,e){var r,i,o,a=sa(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=sa(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:sa(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:sa(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=uo(),c=lr(s),f=I("tick","end");function s(){l(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function l(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.each(function(t){t(e)}),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function h(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=Ta*Math.sqrt(e),o=e*Sa;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function d(n){return n.initialize&&n.initialize(t),n}return null==t&&(t=[]),h(),n={tick:l,restart:function(){return c.restart(s),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,h(),u.each(d),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},force:function(t,e){return arguments.length>1?(null==e?u.remove(t):u.set(t,d(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=sa(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=sa(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:sa(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:sa(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=sa(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=sa(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:sa(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:sa(+n),a(),o):t},o},t.formatDefaultLocale=Fa,t.formatLocale=Ya,t.formatSpecifier=za,t.geoAlbers=Zs,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=Zs(),u=Ws().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=Ws().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+Wa,s+.12*n+Wa],[o-.214*n-Wa,s+.234*n-Wa]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+Wa,s+.166*n+Wa],[o-.115*n-Wa,s+.234*n-Wa]]).stream(f),l()},s.fitExtent=function(t,n){return Ls(s,t,n)},s.fitSize=function(t,n){return Us(s,t,n)},s.fitWidth=function(t,n){return Os(s,t,n)},s.fitHeight=function(t,n){return Bs(s,t,n)},s.scale(1070)},t.geoArea=function(t){return Pu.reset(),Nu(t,zu),2*Pu},t.geoAzimuthalEqualArea=function(){return Xs(Js).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=Js,t.geoAzimuthalEquidistant=function(){return Xs(tl).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=tl,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Vu=Gu=-(ju=Xu=1/0),Ku=[],Nu(t,yc),e=Ku.length){for(Ku.sort(Tc),n=1,o=[r=Ku[0]];n<e;++n)Sc(r,(i=Ku[n])[0])||Sc(r,i[1])?(Ac(r[0],i[1])>Ac(r[0],r[1])&&(r[1]=i[1]),Ac(i[0],r[1])>Ac(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=Ac(r[1],i[0]))>a&&(a=u,ju=i[0],Gu=r[1])}return Ku=Ju=null,ju===1/0||Xu===1/0?[[NaN,NaN],[NaN,NaN]]:[[ju,Xu],[Gu,Vu]]},t.geoCentroid=function(t){tc=nc=ec=rc=ic=oc=ac=uc=cc=fc=sc=0,Nu(t,kc);var n=cc,e=fc,r=sc,i=n*n+e*e+r*r;return i<Za&&(n=oc,e=ac,r=uc,nc<Wa&&(n=ec,e=rc,r=ic),(i=n*n+e*e+r*r)<Za)?[NaN,NaN]:[ou(e,n)*nu,gu(r/du(i))*nu]},t.geoCircle=function(){var t,n,e=Bc([0,0]),r=Bc(90),i=Bc(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=nu,e[1]*=nu}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*eu,c=i.apply(this,arguments)*eu;return t=[],n=Ic(-a[0]*eu,-a[1]*eu,0).invert,Vc(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:Bc([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:Bc(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:Bc(+t),a):i},a},t.geoClipAntimeridian=uf,t.geoClipCircle=cf,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=lf(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=lf,t.geoConicConformal=function(){return Vs(il).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=il,t.geoConicEqualArea=Ws,t.geoConicEqualAreaRaw=$s,t.geoConicEquidistant=function(){return Vs(al).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=al,t.geoContains=function(t,n){return(t&&Nf.hasOwnProperty(t.type)?Nf[t.type]:Tf)(t,n)},t.geoDistance=Mf,t.geoEqualEarth=function(){return Xs(hl).scale(177.158)},t.geoEqualEarthRaw=hl,t.geoEquirectangular=function(){return Xs(ol).scale(152.63)},t.geoEquirectangularRaw=ol,t.geoGnomonic=function(){return Xs(dl).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=dl,t.geoGraticule=Df,t.geoGraticule10=function(){return Df()()},t.geoIdentity=function(){var t,n,e,r,i,o,a=1,u=0,c=0,f=1,s=1,l=qf,h=null,d=qf;function p(){return r=i=null,o}return o={stream:function(t){return r&&i===t?r:r=l(d(i=t))},postclip:function(r){return arguments.length?(d=r,h=t=n=e=null,p()):d},clipExtent:function(r){return arguments.length?(d=null==r?(h=t=n=e=null,qf):lf(h=+r[0][0],t=+r[0][1],n=+r[1][0],e=+r[1][1]),p()):null==h?null:[[h,t],[n,e]]},scale:function(t){return arguments.length?(l=pl((a=+t)*f,a*s,u,c),p()):a},translate:function(t){return arguments.length?(l=pl(a*f,a*s,u=+t[0],c=+t[1]),p()):[u,c]},reflectX:function(t){return arguments.length?(l=pl(a*(f=t?-1:1),a*s,u,c),p()):f<0},reflectY:function(t){return arguments.length?(l=pl(a*f,a*(s=t?-1:1),u,c),p()):s<0},fitExtent:function(t,n){return Ls(o,t,n)},fitSize:function(t,n){return Us(o,t,n)},fitWidth:function(t,n){return Os(o,t,n)},fitHeight:function(t,n){return Bs(o,t,n)}}},t.geoInterpolate=function(t,n){var e=t[0]*eu,r=t[1]*eu,i=n[0]*eu,o=n[1]*eu,a=au(r),u=lu(r),c=au(o),f=lu(o),s=a*au(e),l=a*lu(e),h=c*au(i),d=c*lu(i),p=2*gu(du(yu(o-r)+a*c*yu(i-e))),v=lu(p),g=p?function(t){var n=lu(t*=p)/v,e=lu(p-t)/v,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[ou(i,r)*nu,ou(o,du(r*r+i*i))*nu]}:function(){return[e*nu,r*nu]};return g.distance=p,g},t.geoLength=mf,t.geoMercator=function(){return el(nl).scale(961/tu)},t.geoMercatorRaw=nl,t.geoNaturalEarth1=function(){return Xs(vl).scale(175.295)},t.geoNaturalEarth1Raw=vl,t.geoOrthographic=function(){return Xs(gl).scale(249.5).clipAngle(90+Wa)},t.geoOrthographicRaw=gl,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),Nu(t,e(r))),r.result()}return o.area=function(t){return Nu(t,e(If)),If.result()},o.measure=function(t){return Nu(t,e(ks)),ks.result()},o.bounds=function(t){return Nu(t,e(Qf)),Qf.result()},o.centroid=function(t){return Nu(t,e(ls)),ls.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,qf):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new Ps):new xs(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoProjection=Xs,t.geoProjectionMutator=Gs,t.geoRotation=Gc,t.geoStereographic=function(){return Xs(yl).scale(250).clipAngle(142)},t.geoStereographicRaw=yl,t.geoStream=Nu,t.geoTransform=function(t){return{stream:Rs(t)}},t.geoTransverseMercator=function(){var t=el(_l),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=_l,t.gray=function(t,n){return new Yn(t,0,0,null==n?1:n)},t.hcl=Gn,t.hierarchy=Ml,t.histogram=function(){var t=v,n=s,e=M;function r(r){var o,a,u=r.length,c=new Array(u);for(o=0;o<u;++o)c[o]=t(r[o],o,r);var f=n(c),s=f[0],l=f[1],h=e(c,s,l);Array.isArray(h)||(h=w(s,l,h),h=g(Math.ceil(s/h)*h,l,h));for(var d=h.length;h[0]<=s;)h.shift(),--d;for(;h[d-1]>l;)h.pop(),--d;var p,v=new Array(d+1);for(o=0;o<=d;++o)(p=v[o]=[]).x0=o>0?h[o-1]:s,p.x1=o<d?h[o]:l;for(o=0;o<u;++o)s<=(a=c[o])&&a<=l&&v[i(h,a,0,d)].push(r[o]);return v}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:p(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:p([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?p(h.call(t)):p(t),r):e},r},t.hsl=Tn,t.html=ca,t.image=function(t,n){return new Promise(function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t})},t.interpolate=Ne,t.interpolateArray=ye,t.interpolateBasis=ae,t.interpolateBasisClosed=ue,t.interpolateBlues=Xg,t.interpolateBrBG=rg,t.interpolateBuGn=xg,t.interpolateBuPu=Mg,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=iy,t.interpolateCubehelix=We,t.interpolateCubehelixDefault=ey,t.interpolateCubehelixLong=Ze,t.interpolateDate=_e,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=Ag,t.interpolateGreens=Vg,t.interpolateGreys=Wg,t.interpolateHcl=Ge,t.interpolateHclLong=Ve,t.interpolateHsl=He,t.interpolateHslLong=je,t.interpolateHue=function(t,n){var e=se(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=hy,t.interpolateLab=function(t,n){var e=he((t=Bn(t)).l,(n=Bn(n)).l),r=he(t.a,n.a),i=he(t.b,n.b),o=he(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=ly,t.interpolateNumber=be,t.interpolateObject=me,t.interpolateOrRd=Sg,t.interpolateOranges=ny,t.interpolatePRGn=og,t.interpolatePiYG=ug,t.interpolatePlasma=dy,t.interpolatePuBu=Pg,t.interpolatePuBuGn=Eg,t.interpolatePuOr=fg,t.interpolatePuRd=Rg,t.interpolatePurples=Qg,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return oy.h=360*t-100,oy.s=1.5-1.5*n,oy.l=.8-.9*n,oy+""},t.interpolateRdBu=lg,t.interpolateRdGy=dg,t.interpolateRdPu=qg,t.interpolateRdYlBu=vg,t.interpolateRdYlGn=yg,t.interpolateReds=Jg,t.interpolateRgb=de,t.interpolateRgbBasis=ve,t.interpolateRgbBasisClosed=ge,t.interpolateRound=Ae,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,ay.r=255*(n=Math.sin(t))*n,ay.g=255*(n=Math.sin(t+uy))*n,ay.b=255*(n=Math.sin(t+cy))*n,ay+""},t.interpolateSpectral=bg,t.interpolateString=Me,t.interpolateTransformCss=De,t.interpolateTransformSvg=qe,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=sy,t.interpolateWarm=ry,t.interpolateYlGn=Bg,t.interpolateYlGnBu=Ug,t.interpolateYlOrBr=Fg,t.interpolateYlOrRd=Hg,t.interpolateZoom=Fe,t.interrupt=Cr,t.interval=function(t,n,e){var r=new sr,i=n;return null==n?(r.restart(t,n,e),r):(n=+n,e=null==e?cr():+e,r.restart(function o(a){a+=i,r.restart(o,i+=n,e),t(a)},n,e),r)},t.isoFormat=Sv,t.isoParse=kv,t.json=function(t,n){return fetch(t,n).then(oa)},t.keys=function(t){var n=[];for(var e in t)n.push(e);return n},t.lab=Bn,t.lch=function(t,n,e,r){return 1===arguments.length?Xn(t):new Vn(e,n,t,null==r?1:r)},t.line=Uy,t.lineRadial=Xy,t.linkHorizontal=function(){return Qy(Ky)},t.linkRadial=function(){var t=Qy(t_);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return Qy(Jy)},t.local=qt,t.map=uo,t.matcher=nt,t.max=A,t.mean=function(t,n){var e,r=t.length,i=r,o=-1,a=0;if(null==n)for(;++o<r;)isNaN(e=u(t[o]))?--i:a+=e;else for(;++o<r;)isNaN(e=u(n(t[o],o,t)))?--i:a+=e;if(i)return a/i},t.median=function(t,e){var r,i=t.length,o=-1,a=[];if(null==e)for(;++o<i;)isNaN(r=u(t[o]))||a.push(r);else for(;++o<i;)isNaN(r=u(e(t[o],o,t)))||a.push(r);return N(a.sort(n),.5)},t.merge=T,t.min=S,t.mouse=Bt,t.namespace=W,t.namespaces=$,t.nest=function(){var t,n,e,r=[],i=[];function o(e,i,a,u){if(i>=r.length)return null!=t&&e.sort(t),null!=n?n(e):e;for(var c,f,s,l=-1,h=e.length,d=r[i++],p=uo(),v=a();++l<h;)(s=p.get(c=d(f=e[l])+""))?s.push(f):p.set(c,[f]);return p.each(function(t,n){u(v,n,o(t,i,a,u))}),v}return e={object:function(t){return o(t,0,co,fo)},map:function(t){return o(t,0,so,lo)},entries:function(t){return function t(e,o){if(++o>r.length)return e;var a,u=i[o-1];return null!=n&&o>=r.length?a=e.entries():(a=[],e.each(function(n,e){a.push({key:e,values:t(n,o)})})),null!=u?a.sort(function(t,n){return u(t.key,n.key)}):a}(o(t,0,so,lo),0)},key:function(t){return r.push(t),e},sortKeys:function(t){return i[r.length-1]=t,e},sortValues:function(n){return t=n,e},rollup:function(t){return n=t,e}}},t.now=cr,t.pack=function(){var t=null,n=1,e=1,r=jl;function i(i){return i.x=n/2,i.y=e/2,t?i.eachBefore(Vl(t)).eachAfter($l(r,.5)).eachBefore(Wl(1)):i.eachBefore(Vl(Gl)).eachAfter($l(jl,1)).eachAfter($l(r,i.r/Math.min(n,e))).eachBefore(Wl(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=Il(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:Xl(+t),i):r},i},t.packEnclose=El,t.packSiblings=function(t){return Fl(t),t},t.pairs=function(t,n){null==n&&(n=a);for(var e=0,r=t.length-1,i=t[0],o=new Array(r<0?0:r);e<r;)o[e]=n(i,i=t[++e]);return o},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&Ql(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(Zl),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=to,t.permute=function(t,n){for(var e=n.length,r=new Array(e);e--;)r[e]=t[n[e]];return r},t.pie=function(){var t=Yy,n=By,e=null,r=py(0),i=py(Ay),o=py(0);function a(a){var u,c,f,s,l,h=a.length,d=0,p=new Array(h),v=new Array(h),g=+r.apply(this,arguments),y=Math.min(Ay,Math.max(-Ay,i.apply(this,arguments)-g)),_=Math.min(Math.abs(y)/h,o.apply(this,arguments)),b=_*(y<0?-1:1);for(u=0;u<h;++u)(l=v[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort(function(t,e){return n(v[t],v[e])}):null!=e&&p.sort(function(t,n){return e(a[t],a[n])}),u=0,f=d?(y-h*b)/d:0;u<h;++u,g=s)c=p[u],s=g+((l=v[c])>0?l*f:0)+b,v[c]={data:a[c],index:u,value:l,startAngle:g,endAngle:s,padAngle:_};return v}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:py(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:py(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:py(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:py(+t),a):o},a},t.piecewise=function(t,n){for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}},t.pointRadial=Vy,t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(vh),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=gh(r),a=gh(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.sqrt(n*n+e*e);return c},t.precisionFixed=Ia,t.precisionPrefix=Ha,t.precisionRound=ja,t.quadtree=ga,t.quantile=N,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.radialArea=Gy,t.radialLine=Xy,t.randomBates=wh,t.randomExponential=Mh,t.randomIrwinHall=xh,t.randomLogNormal=mh,t.randomNormal=bh,t.randomUniform=_h,t.range=g,t.rgb=bn,t.ribbon=function(){var t=no,n=eo,e=ro,r=io,i=oo,o=null;function a(){var a,u=$i.call(arguments),c=t.apply(this,u),f=n.apply(this,u),s=+e.apply(this,(u[0]=c,u)),l=r.apply(this,u)-ji,h=i.apply(this,u)-ji,d=s*Fi(l),p=s*Ii(l),v=+e.apply(this,(u[0]=f,u)),g=r.apply(this,u)-ji,y=i.apply(this,u)-ji;if(o||(o=a=to()),o.moveTo(d,p),o.arc(0,0,s,l,h),l===g&&h===y||(o.quadraticCurveTo(0,0,v*Fi(g),v*Ii(g)),o.arc(0,0,v,g,y)),o.quadraticCurveTo(0,0,d,p),o.closePath(),a)return o=null,a+""||null}return a.radius=function(t){return arguments.length?(e="function"==typeof t?t:Wi(+t),a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:Wi(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:Wi(+t),a):i},a.source=function(n){return arguments.length?(t=n,a):t},a.target=function(t){return arguments.length?(n=t,a):n},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a},t.scaleBand=Ph,t.scaleDiverging=function t(){var n=Hh(Iv()(Dh));return n.copy=function(){return Yv(n,t())},Ah.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=Qh(Iv()).domain([.1,1,10]);return n.copy=function(){return Yv(n,t()).base(n.base())},Ah.apply(n,arguments)},t.scaleDivergingPow=Hv,t.scaleDivergingSqrt=function(){return Hv.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=td(Iv());return n.copy=function(){return Yv(n,t()).constant(n.constant())},Ah.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Sh.call(t,zh),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Sh.call(n,zh):[0,1],Hh(r)},t.scaleImplicit=Eh,t.scaleLinear=function t(){var n=Fh(Dh,Dh);return n.copy=function(){return Bh(n,t())},Nh.apply(n,arguments),Hh(n)},t.scaleLog=function t(){var n=Qh(Yh()).domain([1,10]);return n.copy=function(){return Bh(n,t()).base(n.base())},Nh.apply(n,arguments),n},t.scaleOrdinal=Ch,t.scalePoint=function(){return function t(n){var e=n.copy;return n.padding=n.paddingOuter,delete n.paddingInner,delete n.paddingOuter,n.copy=function(){return t(e())},n}(Ph.apply(null,arguments).paddingInner(1))},t.scalePow=od,t.scaleQuantile=function t(){var e,r=[],o=[],a=[];function u(){var t=0,n=Math.max(1,o.length);for(a=new Array(n-1);++t<n;)a[t-1]=N(r,t/n);return c}function c(t){return isNaN(t=+t)?e:o[i(a,t)]}return c.invertExtent=function(t){var n=o.indexOf(t);return n<0?[NaN,NaN]:[n>0?a[n-1]:r[0],n<a.length?a[n]:r[r.length-1]]},c.domain=function(t){if(!arguments.length)return r.slice();r=[];for(var e,i=0,o=t.length;i<o;++i)null==(e=t[i])||isNaN(e=+e)||r.push(e);return r.sort(n),u()},c.range=function(t){return arguments.length?(o=kh.call(t),u()):o.slice()},c.unknown=function(t){return arguments.length?(e=t,c):e},c.quantiles=function(){return a.slice()},c.copy=function(){return t().domain(r).range(o).unknown(e)},Nh.apply(c,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,o=1,a=[.5],u=[0,1];function c(t){return t<=t?u[i(a,t,0,o)]:n}function f(){var t=-1;for(a=new Array(o);++t<o;)a[t]=((t+1)*r-(t-o)*e)/(o+1);return c}return c.domain=function(t){return arguments.length?(e=+t[0],r=+t[1],f()):[e,r]},c.range=function(t){return arguments.length?(o=(u=kh.call(t)).length-1,f()):u.slice()},c.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,a[0]]:n>=o?[a[o-1],r]:[a[n-1],a[n]]},c.unknown=function(t){return arguments.length?(n=t,c):c},c.thresholds=function(){return a.slice()},c.copy=function(){return t().domain([e,r]).range(u).unknown(n)},Nh.apply(Hh(c),arguments)},t.scaleSequential=function t(){var n=Hh(Bv()(Dh));return n.copy=function(){return Yv(n,t())},Ah.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=Qh(Bv()).domain([1,10]);return n.copy=function(){return Yv(n,t()).base(n.base())},Ah.apply(n,arguments)},t.scaleSequentialPow=Fv,t.scaleSequentialQuantile=function t(){var e=[],r=Dh;function o(t){if(!isNaN(t=+t))return r((i(e,t)-1)/(e.length-1))}return o.domain=function(t){if(!arguments.length)return e.slice();e=[];for(var r,i=0,a=t.length;i<a;++i)null==(r=t[i])||isNaN(r=+r)||e.push(r);return e.sort(n),o},o.interpolator=function(t){return arguments.length?(r=t,o):r},o.copy=function(){return t(r).domain(e)},Ah.apply(o,arguments)},t.scaleSequentialSqrt=function(){return Fv.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=td(Bv());return n.copy=function(){return Yv(n,t()).constant(n.constant())},Ah.apply(n,arguments)},t.scaleSqrt=function(){return od.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=td(Yh());return n.copy=function(){return Bh(n,t()).constant(n.constant())},Nh.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],o=1;function a(t){return t<=t?r[i(e,t,0,o)]:n}return a.domain=function(t){return arguments.length?(e=kh.call(t),o=Math.min(e.length,r.length-1),a):e.slice()},a.range=function(t){return arguments.length?(r=kh.call(t),o=Math.min(e.length,r.length-1),a):r.slice()},a.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},a.unknown=function(t){return arguments.length?(n=t,a):n},a.copy=function(){return t().domain(e).range(r).unknown(n)},Nh.apply(a,arguments)},t.scaleTime=function(){return Nh.apply(Ov(Od,Ld,wd,bd,yd,vd,dd,fd,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return Nh.apply(Ov(fp,up,Vd,jd,Id,Yd,dd,fd,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,e){if(r=t.length){var r,i,o=0,a=0,u=t[a];for(null==e&&(e=n);++o<r;)(e(i=t[o],u)<0||0!==e(u,u))&&(u=i,a=o);return 0===e(u,u)?a:void 0}},t.schemeAccent=Gv,t.schemeBlues=jg,t.schemeBrBG=eg,t.schemeBuGn=mg,t.schemeBuPu=wg,t.schemeCategory10=Xv,t.schemeDark2=Vv,t.schemeGnBu=Ng,t.schemeGreens=Gg,t.schemeGreys=$g,t.schemeOrRd=Tg,t.schemeOranges=ty,t.schemePRGn=ig,t.schemePaired=$v,t.schemePastel1=Wv,t.schemePastel2=Zv,t.schemePiYG=ag,t.schemePuBu=Cg,t.schemePuBuGn=kg,t.schemePuOr=cg,t.schemePuRd=zg,t.schemePurples=Zg,t.schemeRdBu=sg,t.schemeRdGy=hg,t.schemeRdPu=Dg,t.schemeRdYlBu=pg,t.schemeRdYlGn=gg,t.schemeReds=Kg,t.schemeSet1=Qv,t.schemeSet2=Kv,t.schemeSet3=Jv,t.schemeSpectral=_g,t.schemeTableau10=tg,t.schemeYlGn=Og,t.schemeYlGnBu=Lg,t.schemeYlOrBr=Yg,t.schemeYlOrRd=Ig,t.select=Rt,t.selectAll=function(t){return"string"==typeof t?new Pt([document.querySelectorAll(t)],[document.documentElement]):new Pt([null==t?[]:t],Ct)},t.selection=zt,t.selector=K,t.selectorAll=tt,t.set=vo,t.shuffle=function(t,n,e){for(var r,i,o=(null==e?t.length:e)-(n=null==n?0:+n);o;)i=Math.random()*o--|0,r=t[o+n],t[o+n]=t[i+n],t[i+n]=r;return t},t.stack=function(){var t=py([]),n=Q_,e=Z_,r=K_;function i(i){var o,a,u=t.apply(this,arguments),c=i.length,f=u.length,s=new Array(f);for(o=0;o<f;++o){for(var l,h=u[o],d=s[o]=new Array(c),p=0;p<c;++p)d[p]=l=[0,+r(i[p],h,p,i)],l.data=i[p];d.key=h}for(o=0,a=n(s);o<f;++o)s[a[o]].index=o;return e(s,a),s}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:py($y.call(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:py(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?Q_:"function"==typeof t?t:py($y.call(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?Z_:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>=0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):r[0]=o},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Z_(t,n)}},t.stackOffsetNone=Z_,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}Z_(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,Z_(t,n)}},t.stackOrderAppearance=J_,t.stackOrderAscending=nb,t.stackOrderDescending=function(t){return nb(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(eb),o=J_(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=Q_,t.stackOrderReverse=function(t){return Q_(t).reverse()},t.stratify=function(){var t=nh,n=eh;function e(e){var r,i,o,a,u,c,f,s=e.length,l=new Array(s),h={};for(i=0;i<s;++i)r=e[i],u=l[i]=new Sl(r),null!=(c=t(r,i,e))&&(c+="")&&(h[f=Kl+(u.id=c)]=f in h?th:u);for(i=0;i<s;++i)if(u=l[i],null!=(c=n(e[i],i,e))&&(c+="")){if(!(a=h[Kl+c]))throw new Error("missing: "+c);if(a===th)throw new Error("ambiguous: "+c);a.children?a.children.push(u):a.children=[u],u.parent=a}else{if(o)throw new Error("multiple roots");o=u}if(!o)throw new Error("no root");if(o.parent=Jl,o.eachBefore(function(t){t.depth=t.parent.depth+1,--s}).eachBefore(Tl),o.parent=null,s>0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=Hl(n),e):t},e.parentId=function(t){return arguments.length?(n=Hl(t),e):n},e},t.style=ft,t.sum=function(t,n){var e,r=t.length,i=-1,o=0;if(null==n)for(;++i<r;)(e=+t[i])&&(o+=e);else for(;++i<r;)(e=+n(t[i],i,t))&&(o+=e);return o},t.svg=fa,t.symbol=function(){var t=py(n_),n=py(64),e=null;function r(){var r;if(e||(e=r=to()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return r.type=function(n){return arguments.length?(t="function"==typeof n?n:py(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:py(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbolCircle=n_,t.symbolCross=e_,t.symbolDiamond=o_,t.symbolSquare=s_,t.symbolStar=f_,t.symbolTriangle=h_,t.symbolWye=g_,t.symbols=y_,t.text=na,t.thresholdFreedmanDiaconis=function(t,e,r){return t=d.call(t,u).sort(n),Math.ceil((r-e)/(2*(N(t,.75)-N(t,.25))*Math.pow(t.length,-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*f(t)*Math.pow(t.length,-1/3)))},t.thresholdSturges=M,t.tickFormat=Ih,t.tickIncrement=x,t.tickStep=w,t.ticks=m,t.timeDay=bd,t.timeDays=md,t.timeFormatDefaultLocale=Tv,t.timeFormatLocale=pp,t.timeFriday=Sd,t.timeFridays=Dd,t.timeHour=yd,t.timeHours=_d,t.timeInterval=cd,t.timeMillisecond=fd,t.timeMilliseconds=sd,t.timeMinute=vd,t.timeMinutes=gd,t.timeMonday=Md,t.timeMondays=Cd,t.timeMonth=Ld,t.timeMonths=Ud,t.timeSaturday=kd,t.timeSaturdays=qd,t.timeSecond=dd,t.timeSeconds=pd,t.timeSunday=wd,t.timeSundays=Ed,t.timeThursday=Td,t.timeThursdays=Rd,t.timeTuesday=Nd,t.timeTuesdays=Pd,t.timeWednesday=Ad,t.timeWednesdays=zd,t.timeWeek=wd,t.timeWeeks=Ed,t.timeYear=Od,t.timeYears=Bd,t.timeout=gr,t.timer=lr,t.timerFlush=hr,t.touch=Yt,t.touches=function(t,n){null==n&&(n=Ut().touches);for(var e=0,r=n?n.length:0,i=new Array(r);e<r;++e)i[e]=Ot(t,n[e]);return i},t.transition=Ur,t.transpose=k,t.tree=function(){var t=rh,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new ch(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new ch(r[i],i)),e.parent=n;return(a.parent=new ch(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore(function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)});var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),v=e/(l.depth||1);i.eachBefore(function(t){t.x=(t.x+d)*p,t.y=t.depth*v})}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=oh(u),o=ih(o),u&&o;)c=ih(c),(a=oh(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(ah(uh(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!oh(a)&&(a.t=u,a.m+=l-s),o&&!ih(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=hh,n=!1,e=1,r=1,i=[0],o=jl,a=jl,u=jl,c=jl,f=jl;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(Zl),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=Hl(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:Xl(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:Xl(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:Xl(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:Xl(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:Xl(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}for(var l=f[n],h=r/2+l,d=n+1,p=e-1;d<p;){var v=d+p>>>1;f[v]<h?d=v+1:p=v}h-f[d-1]<f[d]-h&&n+1<d&&--d;var g=f[d]-l,y=r-g;if(a-i>c-o){var _=(i*y+a*g)/r;t(n,d,g,i,o,_,c),t(d,e,y,_,o,a,c)}else{var b=(o*y+c*g)/r;t(n,d,g,i,o,a,b),t(d,e,y,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=Ql,t.treemapResquarify=dh,t.treemapSlice=fh,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?fh:Ql)(t,n,e,r,i)},t.treemapSquarify=hh,t.tsv=ia,t.tsvFormat=Wo,t.tsvFormatBody=Zo,t.tsvFormatRows=Qo,t.tsvParse=Vo,t.tsvParseRows=$o,t.utcDay=jd,t.utcDays=Xd,t.utcFriday=Kd,t.utcFridays=op,t.utcHour=Id,t.utcHours=Hd,t.utcMillisecond=fd,t.utcMilliseconds=sd,t.utcMinute=Yd,t.utcMinutes=Fd,t.utcMonday=$d,t.utcMondays=np,t.utcMonth=up,t.utcMonths=cp,t.utcSaturday=Jd,t.utcSaturdays=ap,t.utcSecond=dd,t.utcSeconds=pd,t.utcSunday=Vd,t.utcSundays=tp,t.utcThursday=Qd,t.utcThursdays=ip,t.utcTuesday=Wd,t.utcTuesdays=ep,t.utcWednesday=Zd,t.utcWednesdays=rp,t.utcWeek=Vd,t.utcWeeks=tp,t.utcYear=fp,t.utcYears=sp,t.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},t.variance=c,t.version="5.12.0",t.voronoi=function(){var t=ib,n=ob,e=null;function r(r){return new Yb(r.map(function(e,i){var o=[Math.round(t(e,i,r)/Lb)*Lb,Math.round(n(e,i,r)/Lb)*Lb];return o.index=i,o.data=e,o}),e)}return r.polygons=function(t){return r(t).polygons()},r.links=function(t){return r(t).links()},r.triangles=function(t){return r(t).triangles()},r.x=function(n){return arguments.length?(t="function"==typeof n?n:rb(+n),r):t},r.y=function(t){return arguments.length?(n="function"==typeof t?t:rb(+t),r):n},r.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],r):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},r.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],r):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},r},t.window=ct,t.xml=ua,t.zip=function(){return k(arguments)},t.zoom=function(){var n,e,r=$b,i=Wb,o=Jb,a=Qb,u=Kb,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=Fe,h=I("start","zoom","end"),d=500,p=150,v=0;function g(t){t.property("__zoom",Zb).on("wheel.zoom",M).on("mousedown.zoom",N).on("dblclick.zoom",A).filter(u).on("touchstart.zoom",T).on("touchmove.zoom",S).on("touchend.zoom touchcancel.zoom",k).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function y(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new Hb(n,t.x,t.y)}function _(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new Hb(t.k,r,i)}function b(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function m(t,n,e){t.on("start.zoom",function(){x(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){x(this,arguments).end()}).tween("zoom",function(){var t=this,r=arguments,o=x(t,r),a=i.apply(t,r),u=null==e?b(a):"function"==typeof e?e.apply(t,r):e,c=Math.max(a[1][0]-a[0][0],a[1][1]-a[0][1]),f=t.__zoom,s="function"==typeof n?n.apply(t,r):n,h=l(f.invert(u).concat(c/f.k),s.invert(u).concat(c/s.k));return function(t){if(1===t)t=s;else{var n=h(t),e=c/n[2];t=new Hb(e,u[0]-n[0]*e,u[1]-n[1]*e)}o.zoom(null,t)}})}function x(t,n,e){return!e&&t.__zooming||new w(t,n)}function w(t,n){this.that=t,this.args=n,this.active=0,this.extent=i.apply(t,n),this.taps=0}function M(){if(r.apply(this,arguments)){var t=x(this,arguments),n=this.__zoom,e=Math.max(c[0],Math.min(c[1],n.k*Math.pow(2,a.apply(this,arguments)))),i=Bt(this);if(t.wheel)t.mouse[0][0]===i[0]&&t.mouse[0][1]===i[1]||(t.mouse[1]=n.invert(t.mouse[0]=i)),clearTimeout(t.wheel);else{if(n.k===e)return;t.mouse=[i,n.invert(i)],Cr(this),t.start()}Vb(),t.wheel=setTimeout(function(){t.wheel=null,t.end()},p),t.zoom("mouse",o(_(y(n,e),t.mouse[0],t.mouse[1]),t.extent,f))}}function N(){if(!e&&r.apply(this,arguments)){var n=x(this,arguments,!0),i=Rt(t.event.view).on("mousemove.zoom",function(){if(Vb(),!n.moved){var e=t.event.clientX-u,r=t.event.clientY-c;n.moved=e*e+r*r>v}n.zoom("mouse",o(_(n.that.__zoom,n.mouse[0]=Bt(n.that),n.mouse[1]),n.extent,f))},!0).on("mouseup.zoom",function(){i.on("mousemove.zoom mouseup.zoom",null),jt(t.event.view,n.moved),Vb(),n.end()},!0),a=Bt(this),u=t.event.clientX,c=t.event.clientY;Ht(t.event.view),Gb(),n.mouse=[a,this.__zoom.invert(a)],Cr(this),n.start()}}function A(){if(r.apply(this,arguments)){var n=this.__zoom,e=Bt(this),a=n.invert(e),u=n.k*(t.event.shiftKey?.5:2),c=o(_(y(n,u),e,a),i.apply(this,arguments),f);Vb(),s>0?Rt(this).transition().duration(s).call(m,c,e):Rt(this).call(g.transform,c)}}function T(){if(r.apply(this,arguments)){var e,i,o,a,u=t.event.touches,c=u.length,f=x(this,arguments,t.event.changedTouches.length===c);for(Gb(),i=0;i<c;++i)a=[a=Yt(this,u,(o=u[i]).identifier),this.__zoom.invert(a),o.identifier],f.touch0?f.touch1||f.touch0[2]===a[2]||(f.touch1=a,f.taps=0):(f.touch0=a,e=!0,f.taps=1+!!n);n&&(n=clearTimeout(n)),e&&(f.taps<2&&(n=setTimeout(function(){n=null},d)),Cr(this),f.start())}}function S(){if(this.__zooming){var e,r,i,a,u=x(this,arguments),c=t.event.changedTouches,s=c.length;for(Vb(),n&&(n=clearTimeout(n)),u.taps=0,e=0;e<s;++e)i=Yt(this,c,(r=c[e]).identifier),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],v=(v=d[0]-l[0])*v+(v=d[1]-l[1])*v,g=(g=p[0]-h[0])*g+(g=p[1]-h[1])*g;r=y(r,Math.sqrt(v/g)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(_(r,i,a),u.extent,f))}}function k(){if(this.__zooming){var n,r,i=x(this,arguments),o=t.event.changedTouches,a=o.length;for(Gb(),e&&clearTimeout(e),e=setTimeout(function(){e=null},d),n=0;n<a;++n)r=o[n],i.touch0&&i.touch0[2]===r.identifier?delete i.touch0:i.touch1&&i.touch1[2]===r.identifier&&delete i.touch1;if(i.touch1&&!i.touch0&&(i.touch0=i.touch1,delete i.touch1),i.touch0)i.touch0[1]=this.__zoom.invert(i.touch0[0]);else if(i.end(),2===i.taps){var u=Rt(this).on("dblclick.zoom");u&&u.apply(this,arguments)}}}return g.transform=function(t,n,e){var r=t.selection?t.selection():t;r.property("__zoom",Zb),t!==r?m(t,n,e):r.interrupt().each(function(){x(this,arguments).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()})},g.scaleBy=function(t,n,e){g.scaleTo(t,function(){var t=this.__zoom.k,e="function"==typeof n?n.apply(this,arguments):n;return t*e},e)},g.scaleTo=function(t,n,e){g.transform(t,function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?b(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(_(y(r,c),a,u),t,f)},e)},g.translateBy=function(t,n,e){g.transform(t,function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)})},g.translateTo=function(t,n,e,r){g.transform(t,function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?b(t):"function"==typeof r?r.apply(this,arguments):r;return o(jb.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)},r)},w.prototype={start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){kt(new Ib(g,t,this.that.__zoom),h.apply,h,[t,this.that,this.args])}},g.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:Fb(+t),g):a},g.filter=function(t){return arguments.length?(r="function"==typeof t?t:Fb(!!t),g):r},g.touchable=function(t){return arguments.length?(u="function"==typeof t?t:Fb(!!t),g):u},g.extent=function(t){return arguments.length?(i="function"==typeof t?t:Fb([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),g):i},g.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],g):[c[0],c[1]]},g.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],g):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},g.constrain=function(t){return arguments.length?(o=t,g):o},g.duration=function(t){return arguments.length?(s=+t,g):s},g.interpolate=function(t){return arguments.length?(l=t,g):l},g.on=function(){var t=h.on.apply(h,arguments);return t===h?g:t},g.clickDistance=function(t){return arguments.length?(v=(t=+t)*t,g):Math.sqrt(v)},g},t.zoomIdentity=jb,t.zoomTransform=Xb,Object.defineProperty(t,"__esModule",{value:!0})});

</script>
     <script type="text/javascript">
/**
 * Simple, lightweight, usable local autocomplete library for modern browsers
 * Because there weren’t enough autocomplete scripts in the world? Because I’m completely insane and have NIH syndrome? Probably both. :P
 * @author Lea Verou http://leaverou.github.io/awesomplete
 * MIT license
 */

(function () {

var _ = function (input, o) {
	var me = this;

	// Setup

	this.isOpened = false;

	this.input = $(input);
	this.input.setAttribute("autocomplete", "off");
	this.input.setAttribute("aria-autocomplete", "list");

	o = o || {};

	configure(this, {
		minChars: 2,
		maxItems: 10,
		autoFirst: false,
		data: _.DATA,
		filter: _.FILTER_CONTAINS,
		sort: _.SORT_BYLENGTH,
		item: _.ITEM,
		replace: _.REPLACE
	}, o);

	this.index = -1;

	// Create necessary elements

	this.container = $.create("div", {
		className: "awesomplete",
		around: input
	});

	this.ul = $.create("ul", {
		hidden: "hidden",
		inside: this.container
	});

	this.status = $.create("span", {
		className: "visually-hidden",
		role: "status",
		"aria-live": "assertive",
		"aria-relevant": "additions",
		inside: this.container
	});

	// Bind events

	$.bind(this.input, {
		"input": this.evaluate.bind(this),
		"blur": this.close.bind(this, { reason: "blur" }),
		"keydown": function(evt) {
			var c = evt.keyCode;

			// If the dropdown `ul` is in view, then act on keydown for the following keys:
			// Enter / Esc / Up / Down
			if(me.opened) {
				if (c === 13 && me.selected) { // Enter
					evt.preventDefault();
					me.select();
				}
				else if (c === 27) { // Esc
					me.close({ reason: "esc" });
				}
				else if (c === 38 || c === 40) { // Down/Up arrow
					evt.preventDefault();
					me[c === 38? "previous" : "next"]();
				}
			}
		}
	});

	$.bind(this.input.form, {"submit": this.close.bind(this, { reason: "submit" })});

	$.bind(this.ul, {"mousedown": function(evt) {
		var li = evt.target;

		if (li !== this) {

			while (li && !/li/i.test(li.nodeName)) {
				li = li.parentNode;
			}

			if (li && evt.button === 0) {  // Only select on left click
				evt.preventDefault();
				me.select(li, evt.target);
			}
		}
	}});

	if (this.input.hasAttribute("list")) {
		this.list = "#" + this.input.getAttribute("list");
		this.input.removeAttribute("list");
	}
	else {
		this.list = this.input.getAttribute("data-list") || o.list || [];
	}

	_.all.push(this);
};

_.prototype = {
	set list(list) {
		if (Array.isArray(list)) {
			this._list = list;
		}
		else if (typeof list === "string" && list.indexOf(",") > -1) {
				this._list = list.split(/\s*,\s*/);
		}
		else { // Element or CSS selector
			list = $(list);

			if (list && list.children) {
				var items = [];
				slice.apply(list.children).forEach(function (el) {
					if (!el.disabled) {
						var text = el.textContent.trim();
						var value = el.value || text;
						var label = el.label || text;
						if (value !== "") {
							items.push({ label: label, value: value });
						}
					}
				});
				this._list = items;
			}
		}

		if (document.activeElement === this.input) {
			this.evaluate();
		}
	},

	get selected() {
		return this.index > -1;
	},

	get opened() {
		return this.isOpened;
	},

	close: function (o) {
		if (!this.opened) {
			return;
		}

		this.ul.setAttribute("hidden", "");
		this.isOpened = false;
		this.index = -1;

		$.fire(this.input, "awesomplete-close", o || {});
	},

	open: function () {
		this.ul.removeAttribute("hidden");
		this.isOpened = true;

		if (this.autoFirst && this.index === -1) {
			this.goto(0);
		}

		$.fire(this.input, "awesomplete-open");
	},

	next: function () {
		var count = this.ul.children.length;
		this.goto(this.index < count - 1 ? this.index + 1 : (count ? 0 : -1) );
	},

	previous: function () {
		var count = this.ul.children.length;
		var pos = this.index - 1;

		this.goto(this.selected && pos !== -1 ? pos : count - 1);
	},

	// Should not be used, highlights specific item without any checks!
	goto: function (i) {
		var lis = this.ul.children;

		if (this.selected) {
			lis[this.index].setAttribute("aria-selected", "false");
		}

		this.index = i;

		if (i > -1 && lis.length > 0) {
			lis[i].setAttribute("aria-selected", "true");
			this.status.textContent = lis[i].textContent;

			$.fire(this.input, "awesomplete-highlight", {
				text: this.suggestions[this.index]
			});
		}
	},

	select: function (selected, origin) {
		if (selected) {
			this.index = $.siblingIndex(selected);
		} else {
			selected = this.ul.children[this.index];
		}

		if (selected) {
			var suggestion = this.suggestions[this.index];

			var allowed = $.fire(this.input, "awesomplete-select", {
				text: suggestion,
				origin: origin || selected
			});

			if (allowed) {
				this.replace(suggestion);
				this.close({ reason: "select" });
				$.fire(this.input, "awesomplete-selectcomplete", {
					text: suggestion
				});
			}
		}
	},

	evaluate: function() {
		var me = this;
		var value = this.input.value;

		if (value.length >= this.minChars && this._list.length > 0) {
			this.index = -1;
			// Populate list with options that match
			this.ul.innerHTML = "";

			this.suggestions = this._list
				.map(function(item) {
					return new Suggestion(me.data(item, value));
				})
				.filter(function(item) {
					return me.filter(item, value);
				})
				.sort(this.sort)
				.slice(0, this.maxItems);

			this.suggestions.forEach(function(text) {
					me.ul.appendChild(me.item(text, value));
				});

			if (this.ul.children.length === 0) {
				this.close({ reason: "nomatches" });
			} else {
				this.open();
			}
		}
		else {
			this.close({ reason: "nomatches" });
		}
	}
};

// Static methods/properties

_.all = [];

_.FILTER_CONTAINS = function (text, input) {
	return RegExp($.regExpEscape(input.trim()), "i").test(text);
};

_.FILTER_STARTSWITH = function (text, input) {
	return RegExp("^" + $.regExpEscape(input.trim()), "i").test(text);
};

_.SORT_BYLENGTH = function (a, b) {
	if (a.length !== b.length) {
		return a.length - b.length;
	}

	return a < b? -1 : 1;
};

_.ITEM = function (text, input) {
	var html = input === '' ? text : text.replace(RegExp($.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>");
	return $.create("li", {
		innerHTML: html,
		"aria-selected": "false"
	});
};

_.REPLACE = function (text) {
	this.input.value = text.value;
};

_.DATA = function (item/*, input*/) { return item; };

// Private functions

function Suggestion(data) {
	var o = Array.isArray(data)
	  ? { label: data[0], value: data[1] }
	  : typeof data === "object" && "label" in data && "value" in data ? data : { label: data, value: data };

	this.label = o.label || o.value;
	this.value = o.value;
}
Object.defineProperty(Suggestion.prototype = Object.create(String.prototype), "length", {
	get: function() { return this.label.length; }
});
Suggestion.prototype.toString = Suggestion.prototype.valueOf = function () {
	return "" + this.label;
};

function configure(instance, properties, o) {
	for (var i in properties) {
		var initial = properties[i],
		    attrValue = instance.input.getAttribute("data-" + i.toLowerCase());

		if (typeof initial === "number") {
			instance[i] = parseInt(attrValue);
		}
		else if (initial === false) { // Boolean options must be false by default anyway
			instance[i] = attrValue !== null;
		}
		else if (initial instanceof Function) {
			instance[i] = null;
		}
		else {
			instance[i] = attrValue;
		}

		if (!instance[i] && instance[i] !== 0) {
			instance[i] = (i in o)? o[i] : initial;
		}
	}
}

// Helpers

var slice = Array.prototype.slice;

function $(expr, con) {
	return typeof expr === "string"? (con || document).querySelector(expr) : expr || null;
}

function $$(expr, con) {
	return slice.call((con || document).querySelectorAll(expr));
}

$.create = function(tag, o) {
	var element = document.createElement(tag);

	for (var i in o) {
		var val = o[i];

		if (i === "inside") {
			$(val).appendChild(element);
		}
		else if (i === "around") {
			var ref = $(val);
			ref.parentNode.insertBefore(element, ref);
			element.appendChild(ref);
		}
		else if (i in element) {
			element[i] = val;
		}
		else {
			element.setAttribute(i, val);
		}
	}

	return element;
};

$.bind = function(element, o) {
	if (element) {
		for (var event in o) {
			var callback = o[event];

			event.split(/\s+/).forEach(function (event) {
				element.addEventListener(event, callback);
			});
		}
	}
};

$.fire = function(target, type, properties) {
	var evt = document.createEvent("HTMLEvents");

	evt.initEvent(type, true, true );

	for (var j in properties) {
		evt[j] = properties[j];
	}

	return target.dispatchEvent(evt);
};

$.regExpEscape = function (s) {
	return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
};

$.siblingIndex = function (el) {
	/* eslint-disable no-cond-assign */
	for (var i = 0; el = el.previousElementSibling; i++);
	return i;
};

// Initialization

function init() {
	$$("input.awesomplete").forEach(function (input) {
		new _(input);
	});
}

// Are we in a browser? Check for Document constructor
if (typeof Document !== "undefined") {
	// DOM already loaded?
	if (document.readyState !== "loading") {
		init();
	}
	else {
		// Wait for it
		document.addEventListener("DOMContentLoaded", init);
	}
}

_.$ = $;
_.$$ = $$;

// Make sure to export Awesomplete on self when in a browser
if (typeof self !== "undefined") {
	self.Awesomplete = _;
}

// Expose Awesomplete as a CJS module
if (typeof module === "object" && module.exports) {
	module.exports = _;
}

return _;

}());

</script>
     <script type="text/javascript">
/**
* vkBeautify - javascript plugin to pretty-print or minify text in XML, JSON, CSS and SQL formats.
*
* Version - 0.99.00.beta
* Copyright (c) 2012 Vadim Kiryukhin
* vkiryukhin @ gmail.com
* http://www.eslinstructor.net/vkbeautify/
*
* MIT license:
*   http://www.opensource.org/licenses/mit-license.php
*
*   Pretty print
*
*        vkbeautify.xml(text [,indent_pattern]);
*
*
*        @text - String; text to beatufy;
*        @indent_pattern - Integer | String;
*                Integer:  number of white spaces;
*                String:   character string to visualize indentation ( can also be a set of white spaces )
*/

(function() {

    function createShiftArr(step) {

        var space = '    ';

        if ( isNaN(parseInt(step)) ) {  // argument is string
            space = step;
        } else { // argument is integer
            switch(step) {
                case 1: space = ' '; break;
                case 2: space = '  '; break;
                case 3: space = '   '; break;
                case 4: space = '    '; break;
                case 5: space = '     '; break;
                case 6: space = '      '; break;
                case 7: space = '       '; break;
                case 8: space = '        '; break;
                case 9: space = '         '; break;
                case 10: space = '          '; break;
                case 11: space = '           '; break;
                case 12: space = '            '; break;
            }
        }

        var shift = ['\n']; // array of shifts
        for(ix=0;ix<100;ix++){
            shift.push(shift[ix]+space);
        }
        return shift;
    }

    function vkbeautify(){
        this.step = '\t'; // 4 spaces
        this.shift = createShiftArr(this.step);
    };

    vkbeautify.prototype.xml = function(text,step) {

        var ar = text.replace(/>\s{0,}</g,"><")
                        .replace(/</g,"~::~<")
                        .replace(/\s*xmlns\:/g,"~::~xmlns:")
                        .replace(/\s*xmlns\=/g,"~::~xmlns=")
                        .split('~::~'),
            len = ar.length,
            inComment = false,
            deep = 0,
            str = '',
            ix = 0,
            shift = step ? createShiftArr(step) : this.shift;

            for(ix=0;ix<len;ix++) {
                // start comment or <![CDATA[...]]> or <!DOCTYPE //
                if(ar[ix].search(/<!/) > -1) {
                    str += shift[deep]+ar[ix];
                    inComment = true;
                    // end comment  or <![CDATA[...]]> //
                    if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1 ) {
                        inComment = false;
                    }
                } else
                // end comment  or <![CDATA[...]]> //
                if(ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) {
                    str += ar[ix];
                    inComment = false;
                } else
                // <elm></elm> //
                if( /^<\w/.exec(ar[ix-1]) && /^<\/\w/.exec(ar[ix]) &&
                    /^<[\w:\-\.\,]+/.exec(ar[ix-1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/','')) {
                    str += ar[ix];
                    if(!inComment) deep--;
                } else
                    // <elm> //
                if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1 ) {
                    str = !inComment ? str += shift[deep++]+ar[ix] : str += ar[ix];
                } else
                    // <elm>...</elm> //
                if(ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) {
                    str = !inComment ? str += shift[deep]+ar[ix] : str += ar[ix];
                } else
                // </elm> //
                if(ar[ix].search(/<\//) > -1) {
                    str = !inComment ? str += shift[--deep]+ar[ix] : str += ar[ix];
                } else
                // <elm/> //
                if(ar[ix].search(/\/>/) > -1 ) {
                    str = !inComment ? str += shift[deep]+ar[ix] : str += ar[ix];
                } else
                // <? xml ... ?> //
                if(ar[ix].search(/<\?/) > -1) {
                    str += shift[deep]+ar[ix];
                } else
                // xmlns //
                if( ar[ix].search(/xmlns\:/) > -1  || ar[ix].search(/xmlns\=/) > -1) {
                    str += shift[deep]+ar[ix];
                }

                else {
                    str += ar[ix];
                }
            }

        return  (str[0] == '\n') ? str.slice(1) : str;
    }

    window.vkbeautify = new vkbeautify();

})();
</script>
     <script type="text/javascript">
(function(e){if(typeof exports=="object"&&typeof module!="undefined")module.exports=
e();else if(typeof define=="function"&&define.amd)define([],e);else{var t;typeof 
window!="undefined"?t=window:typeof global!="undefined"?t=global:typeof self!="undefined"?
t=self:t=this,t.pako=e()}})(function(){var e,t,n;return function(){function e(t,
n,i){function s(u,a){if(!n[u]){if(!t[u]){var f="function"==typeof require&&require
;if(!a&&f)return f(u,!0);if(o)return o(u,!0);var l=new Error("Cannot find module '"+
u+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[u]={exports:{}};t[u][0].call(c.
exports,function(e){var n=t[u][1][e];return s(n||e)},c,c.exports,e,t,n,i)}return n
[u].exports}for(var o="function"==typeof require&&require,u=0;u<i.length;u++)s(i
[u]);return s}return e}()({1:[function(e,t,n){"use strict";function i(e,t){return Object
.prototype.hasOwnProperty.call(e,t)}var r=typeof Uint8Array!="undefined"&&typeof 
Uint16Array!="undefined"&&typeof Int32Array!="undefined";n.assign=function(e){var t=
Array.prototype.slice.call(arguments,1);while(t.length){var n=t.shift();if(!n)continue;
if(typeof n!="object")throw new TypeError(n+"must be non-object");for(var r in n
)i(n,r)&&(e[r]=n[r])}return e},n.shrinkBuf=function(e,t){return e.length===t?e:e
.subarray?e.subarray(0,t):(e.length=t,e)};var s={arraySet:function(e,t,n,r,i){if(
t.subarray&&e.subarray){e.set(t.subarray(n,n+r),i);return}for(var s=0;s<r;s++)e[
i+s]=t[n+s]},flattenChunks:function(e){var t,n,r,i,s,o;r=0;for(t=0,n=e.length;t<
n;t++)r+=e[t].length;o=new Uint8Array(r),i=0;for(t=0,n=e.length;t<n;t++)s=e[t],o
.set(s,i),i+=s.length;return o}},o={arraySet:function(e,t,n,r,i){for(var s=0;s<r
;s++)e[i+s]=t[n+s]},flattenChunks:function(e){return[].concat.apply([],e)}};n.setTyped=
function(e){e?(n.Buf8=Uint8Array,n.Buf16=Uint16Array,n.Buf32=Int32Array,n.assign
(n,s)):(n.Buf8=Array,n.Buf16=Array,n.Buf32=Array,n.assign(n,o))},n.setTyped(r)},
{}],2:[function(e,t,n){"use strict";function f(e,t){if(t<65534)if(e.subarray&&s||!
e.subarray&&i)return String.fromCharCode.apply(null,r.shrinkBuf(e,t));var n="";for(
var o=0;o<t;o++)n+=String.fromCharCode(e[o]);return n}var r=e("./common"),i=!0,s=!0
;try{String.fromCharCode.apply(null,[0])}catch(o){i=!1}try{String.fromCharCode.apply
(null,new Uint8Array(1))}catch(o){s=!1}var u=new r.Buf8(256);for(var a=0;a<256;a++
)u[a]=a>=252?6:a>=248?5:a>=240?4:a>=224?3:a>=192?2:1;u[254]=u[254]=1,n.string2buf=
function(e){var t,n,i,s,o,u=e.length,a=0;for(s=0;s<u;s++)n=e.charCodeAt(s),(n&64512
)===55296&&s+1<u&&(i=e.charCodeAt(s+1),(i&64512)===56320&&(n=65536+(n-55296<<10)+
(i-56320),s++)),a+=n<128?1:n<2048?2:n<65536?3:4;t=new r.Buf8(a);for(o=0,s=0;o<a;
s++)n=e.charCodeAt(s),(n&64512)===55296&&s+1<u&&(i=e.charCodeAt(s+1),(i&64512)===56320&&
(n=65536+(n-55296<<10)+(i-56320),s++)),n<128?t[o++]=n:n<2048?(t[o++]=192|n>>>6,t
[o++]=128|n&63):n<65536?(t[o++]=224|n>>>12,t[o++]=128|n>>>6&63,t[o++]=128|n&63):
(t[o++]=240|n>>>18,t[o++]=128|n>>>12&63,t[o++]=128|n>>>6&63,t[o++]=128|n&63);return t
},n.buf2binstring=function(e){return f(e,e.length)},n.binstring2buf=function(e){
var t=new r.Buf8(e.length);for(var n=0,i=t.length;n<i;n++)t[n]=e.charCodeAt(n);return t
},n.buf2string=function(e,t){var n,r,i,s,o=t||e.length,a=new Array(o*2);for(r=0,
n=0;n<o;){i=e[n++];if(i<128){a[r++]=i;continue}s=u[i];if(s>4){a[r++]=65533,n+=s-1
;continue}i&=s===2?31:s===3?15:7;while(s>1&&n<o)i=i<<6|e[n++]&63,s--;if(s>1){a[r++
]=65533;continue}i<65536?a[r++]=i:(i-=65536,a[r++]=55296|i>>10&1023,a[r++]=56320|
i&1023)}return f(a,r)},n.utf8border=function(e,t){var n;t=t||e.length,t>e.length&&
(t=e.length),n=t-1;while(n>=0&&(e[n]&192)===128)n--;return n<0?t:n===0?t:n+u[e[n
]]>t?n:t}},{"./common":1}],3:[function(e,t,n){"use strict";function r(e,t,n,r){var i=
e&65535|0,s=e>>>16&65535|0,o=0;while(n!==0){o=n>2e3?2e3:n,n-=o;do i=i+t[r++]|0,s=
s+i|0;while(--o);i%=65521,s%=65521}return i|s<<16|0}t.exports=r},{}],4:[function(
e,t,n){"use strict";t.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH
:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1
,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED
:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE
:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}}
,{}],5:[function(e,t,n){"use strict";function r(){var e,t=[];for(var n=0;n<256;n++
){e=n;for(var r=0;r<8;r++)e=e&1?3988292384^e>>>1:e>>>1;t[n]=e}return t}function s
(e,t,n,r){var s=i,o=r+n;e^=-1;for(var u=r;u<o;u++)e=e>>>8^s[(e^t[u])&255];return e^-1
}var i=r();t.exports=s},{}],6:[function(e,t,n){"use strict";function r(){this.text=0
,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name=""
,this.comment="",this.hcrc=0,this.done=!1}t.exports=r},{}],7:[function(e,t,n){"use strict"
;var r=30,i=12;t.exports=function(t,n){var s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x
,T,N,C,k,L,A;s=t.state,o=t.next_in,L=t.input,u=o+(t.avail_in-5),a=t.next_out,A=t
.output,f=a-(n-t.avail_out),l=a+(t.avail_out-257),c=s.dmax,h=s.wsize,p=s.whave,d=
s.wnext,v=s.window,m=s.hold,g=s.bits,y=s.lencode,b=s.distcode,w=(1<<s.lenbits)-1
,E=(1<<s.distbits)-1;e:do{g<15&&(m+=L[o++]<<g,g+=8,m+=L[o++]<<g,g+=8),S=y[m&w];t
:for(;;){x=S>>>24,m>>>=x,g-=x,x=S>>>16&255;if(x===0)A[a++]=S&65535;else{if(!(x&16
)){if((x&64)===0){S=y[(S&65535)+(m&(1<<x)-1)];continue t}if(x&32){s.mode=i;break e
}t.msg="invalid literal/length code",s.mode=r;break e}T=S&65535,x&=15,x&&(g<x&&(
m+=L[o++]<<g,g+=8),T+=m&(1<<x)-1,m>>>=x,g-=x),g<15&&(m+=L[o++]<<g,g+=8,m+=L[o++]<<
g,g+=8),S=b[m&E];n:for(;;){x=S>>>24,m>>>=x,g-=x,x=S>>>16&255;if(!(x&16)){if((x&64
)===0){S=b[(S&65535)+(m&(1<<x)-1)];continue n}t.msg="invalid distance code",s.mode=
r;break e}N=S&65535,x&=15,g<x&&(m+=L[o++]<<g,g+=8,g<x&&(m+=L[o++]<<g,g+=8)),N+=m&
(1<<x)-1;if(N>c){t.msg="invalid distance too far back",s.mode=r;break e}m>>>=x,g-=
x,x=a-f;if(N>x){x=N-x;if(x>p&&s.sane){t.msg="invalid distance too far back",s.mode=
r;break e}C=0,k=v;if(d===0){C+=h-x;if(x<T){T-=x;do A[a++]=v[C++];while(--x);C=a-
N,k=A}}else if(d<x){C+=h+d-x,x-=d;if(x<T){T-=x;do A[a++]=v[C++];while(--x);C=0;if(
d<T){x=d,T-=x;do A[a++]=v[C++];while(--x);C=a-N,k=A}}}else{C+=d-x;if(x<T){T-=x;do A
[a++]=v[C++];while(--x);C=a-N,k=A}}while(T>2)A[a++]=k[C++],A[a++]=k[C++],A[a++]=
k[C++],T-=3;T&&(A[a++]=k[C++],T>1&&(A[a++]=k[C++]))}else{C=a-N;do A[a++]=A[C++],
A[a++]=A[C++],A[a++]=A[C++],T-=3;while(T>2);T&&(A[a++]=A[C++],T>1&&(A[a++]=A[C++
]))}break}}break}}while(o<u&&a<l);T=g>>3,o-=T,g-=T<<3,m&=(1<<g)-1,t.next_in=o,t.
next_out=a,t.avail_in=o<u?5+(u-o):5-(o-u),t.avail_out=a<l?257+(l-a):257-(a-l),s.
hold=m,s.bits=g;return}},{}],8:[function(e,t,n){"use strict";function it(e){return(
e>>>24&255)+(e>>>8&65280)+((e&65280)<<8)+((e&255)<<24)}function st(){this.mode=0
,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0
,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0
,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0
,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0
,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new r.Buf16(320),
this.work=new r.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0
,this.was=0}function ot(e){var t;return!e||!e.state?g:(t=e.state,e.total_in=e.total_out=
t.total=0,e.msg="",t.wrap&&(e.adler=t.wrap&1),t.mode=S,t.last=0,t.havedict=0,t.dmax=32768
,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new r.Buf32(et),t.distcode=t.distdyn=new 
r.Buf32(tt),t.sane=1,t.back=-1,d)}function ut(e){var t;return!e||!e.state?g:(t=e
.state,t.wsize=0,t.whave=0,t.wnext=0,ot(e))}function at(e,t){var n,r;return!e||!
e.state?g:(r=e.state,t<0?(n=0,t=-t):(n=(t>>4)+1,t<48&&(t&=15)),t&&(t<8||t>15)?g:
(r.window!==null&&r.wbits!==t&&(r.window=null),r.wrap=n,r.wbits=t,ut(e)))}function ft
(e,t){var n,r;return e?(r=new st,e.state=r,r.window=null,n=at(e,t),n!==d&&(e.state=
null),n):g}function lt(e){return ft(e,rt)}function dt(e){if(ct){var t;ht=new r.Buf32
(512),pt=new r.Buf32(32),t=0;while(t<144)e.lens[t++]=8;while(t<256)e.lens[t++]=9
;while(t<280)e.lens[t++]=7;while(t<288)e.lens[t++]=8;u(f,e.lens,0,288,ht,0,e.work
,{bits:9}),t=0;while(t<32)e.lens[t++]=5;u(l,e.lens,0,32,pt,0,e.work,{bits:5}),ct=!1
}e.lencode=ht,e.lenbits=9,e.distcode=pt,e.distbits=5}function vt(e,t,n,i){var s,
o=e.state;return o.window===null&&(o.wsize=1<<o.wbits,o.wnext=0,o.whave=0,o.window=new 
r.Buf8(o.wsize)),i>=o.wsize?(r.arraySet(o.window,t,n-o.wsize,o.wsize,0),o.wnext=0
,o.whave=o.wsize):(s=o.wsize-o.wnext,s>i&&(s=i),r.arraySet(o.window,t,n-i,s,o.wnext
),i-=s,i?(r.arraySet(o.window,t,n-i,i,0),o.wnext=i,o.whave=o.wsize):(o.wnext+=s,
o.wnext===o.wsize&&(o.wnext=0),o.whave<o.wsize&&(o.whave+=s))),0}function mt(e,t
){var n,et,tt,nt,rt,st,ot,ut,at,ft,lt,ct,ht,pt,mt=0,gt,yt,bt,wt,Et,St,xt,Tt,Nt=new 
r.Buf8(4),Ct,kt,Lt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!e||!e.state||!
e.output||!e.input&&e.avail_in!==0)return g;n=e.state,n.mode===D&&(n.mode=P),rt=
e.next_out,tt=e.output,ot=e.avail_out,nt=e.next_in,et=e.input,st=e.avail_in,ut=n
.hold,at=n.bits,ft=st,lt=ot,Tt=d;e:for(;;)switch(n.mode){case S:if(n.wrap===0){n
.mode=P;break}while(at<16){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}if(n.wrap&2&&
ut===35615){n.check=0,Nt[0]=ut&255,Nt[1]=ut>>>8&255,n.check=s(n.check,Nt,2,0),ut=0
,at=0,n.mode=x;break}n.flags=0,n.head&&(n.head.done=!1);if(!(n.wrap&1)||(((ut&255
)<<8)+(ut>>8))%31){e.msg="incorrect header check",n.mode=G;break}if((ut&15)!==E)
{e.msg="unknown compression method",n.mode=G;break}ut>>>=4,at-=4,xt=(ut&15)+8;if(
n.wbits===0)n.wbits=xt;else if(xt>n.wbits){e.msg="invalid window size",n.mode=G;
break}n.dmax=1<<xt,e.adler=n.check=1,n.mode=ut&512?M:D,ut=0,at=0;break;case x:while(
at<16){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}n.flags=ut;if((n.flags&255)!==
E){e.msg="unknown compression method",n.mode=G;break}if(n.flags&57344){e.msg="unknown header flags set"
,n.mode=G;break}n.head&&(n.head.text=ut>>8&1),n.flags&512&&(Nt[0]=ut&255,Nt[1]=ut>>>8&255
,n.check=s(n.check,Nt,2,0)),ut=0,at=0,n.mode=T;case T:while(at<32){if(st===0)break e
;st--,ut+=et[nt++]<<at,at+=8}n.head&&(n.head.time=ut),n.flags&512&&(Nt[0]=ut&255
,Nt[1]=ut>>>8&255,Nt[2]=ut>>>16&255,Nt[3]=ut>>>24&255,n.check=s(n.check,Nt,4,0))
,ut=0,at=0,n.mode=N;case N:while(at<16){if(st===0)break e;st--,ut+=et[nt++]<<at,
at+=8}n.head&&(n.head.xflags=ut&255,n.head.os=ut>>8),n.flags&512&&(Nt[0]=ut&255,
Nt[1]=ut>>>8&255,n.check=s(n.check,Nt,2,0)),ut=0,at=0,n.mode=C;case C:if(n.flags&1024
){while(at<16){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}n.length=ut,n.head&&
(n.head.extra_len=ut),n.flags&512&&(Nt[0]=ut&255,Nt[1]=ut>>>8&255,n.check=s(n.check
,Nt,2,0)),ut=0,at=0}else n.head&&(n.head.extra=null);n.mode=k;case k:if(n.flags&1024
){ct=n.length,ct>st&&(ct=st),ct&&(n.head&&(xt=n.head.extra_len-n.length,n.head.extra||
(n.head.extra=new Array(n.head.extra_len)),r.arraySet(n.head.extra,et,nt,ct,xt))
,n.flags&512&&(n.check=s(n.check,et,ct,nt)),st-=ct,nt+=ct,n.length-=ct);if(n.length
)break e}n.length=0,n.mode=L;case L:if(n.flags&2048){if(st===0)break e;ct=0;do xt=
et[nt+ct++],n.head&&xt&&n.length<65536&&(n.head.name+=String.fromCharCode(xt));while(
xt&&ct<st);n.flags&512&&(n.check=s(n.check,et,ct,nt)),st-=ct,nt+=ct;if(xt)break e
}else n.head&&(n.head.name=null);n.length=0,n.mode=A;case A:if(n.flags&4096){if(
st===0)break e;ct=0;do xt=et[nt+ct++],n.head&&xt&&n.length<65536&&(n.head.comment+=
String.fromCharCode(xt));while(xt&&ct<st);n.flags&512&&(n.check=s(n.check,et,ct,
nt)),st-=ct,nt+=ct;if(xt)break e}else n.head&&(n.head.comment=null);n.mode=O;case O
:if(n.flags&512){while(at<16){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}if(ut!==
(n.check&65535)){e.msg="header crc mismatch",n.mode=G;break}ut=0,at=0}n.head&&(n
.head.hcrc=n.flags>>9&1,n.head.done=!0),e.adler=n.check=0,n.mode=D;break;case M:
while(at<32){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}e.adler=n.check=it(ut
),ut=0,at=0,n.mode=_;case _:if(n.havedict===0)return e.next_out=rt,e.avail_out=ot
,e.next_in=nt,e.avail_in=st,n.hold=ut,n.bits=at,m;e.adler=n.check=1,n.mode=D;case D
:if(t===h||t===p)break e;case P:if(n.last){ut>>>=at&7,at-=at&7,n.mode=J;break}while(
at<3){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}n.last=ut&1,ut>>>=1,at-=1;switch(
ut&3){case 0:n.mode=H;break;case 1:dt(n),n.mode=R;if(t===p){ut>>>=2,at-=2;break e
}break;case 2:n.mode=F;break;case 3:e.msg="invalid block type",n.mode=G}ut>>>=2,
at-=2;break;case H:ut>>>=at&7,at-=at&7;while(at<32){if(st===0)break e;st--,ut+=et
[nt++]<<at,at+=8}if((ut&65535)!==(ut>>>16^65535)){e.msg="invalid stored block lengths"
,n.mode=G;break}n.length=ut&65535,ut=0,at=0,n.mode=B;if(t===p)break e;case B:n.mode=
j;case j:ct=n.length;if(ct){ct>st&&(ct=st),ct>ot&&(ct=ot);if(ct===0)break e;r.arraySet
(tt,et,nt,ct,rt),st-=ct,nt+=ct,ot-=ct,rt+=ct,n.length-=ct;break}n.mode=D;break;case F
:while(at<14){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}n.nlen=(ut&31)+257,ut>>>=5
,at-=5,n.ndist=(ut&31)+1,ut>>>=5,at-=5,n.ncode=(ut&15)+4,ut>>>=4,at-=4;if(n.nlen>286||
n.ndist>30){e.msg="too many length or distance symbols",n.mode=G;break}n.have=0,
n.mode=I;case I:while(n.have<n.ncode){while(at<3){if(st===0)break e;st--,ut+=et[
nt++]<<at,at+=8}n.lens[Lt[n.have++]]=ut&7,ut>>>=3,at-=3}while(n.have<19)n.lens[Lt
[n.have++]]=0;n.lencode=n.lendyn,n.lenbits=7,Ct={bits:n.lenbits},Tt=u(a,n.lens,0
,19,n.lencode,0,n.work,Ct),n.lenbits=Ct.bits;if(Tt){e.msg="invalid code lengths set"
,n.mode=G;break}n.have=0,n.mode=q;case q:while(n.have<n.nlen+n.ndist){for(;;){mt=
n.lencode[ut&(1<<n.lenbits)-1],gt=mt>>>24,yt=mt>>>16&255,bt=mt&65535;if(gt<=at)break;
if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}if(bt<16)ut>>>=gt,at-=gt,n.lens[n.
have++]=bt;else{if(bt===16){kt=gt+2;while(at<kt){if(st===0)break e;st--,ut+=et[nt++
]<<at,at+=8}ut>>>=gt,at-=gt;if(n.have===0){e.msg="invalid bit length repeat",n.mode=
G;break}xt=n.lens[n.have-1],ct=3+(ut&3),ut>>>=2,at-=2}else if(bt===17){kt=gt+3;while(
at<kt){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}ut>>>=gt,at-=gt,xt=0,ct=3+(
ut&7),ut>>>=3,at-=3}else{kt=gt+7;while(at<kt){if(st===0)break e;st--,ut+=et[nt++
]<<at,at+=8}ut>>>=gt,at-=gt,xt=0,ct=11+(ut&127),ut>>>=7,at-=7}if(n.have+ct>n.nlen+
n.ndist){e.msg="invalid bit length repeat",n.mode=G;break}while(ct--)n.lens[n.have++
]=xt}}if(n.mode===G)break;if(n.lens[256]===0){e.msg="invalid code -- missing end-of-block"
,n.mode=G;break}n.lenbits=9,Ct={bits:n.lenbits},Tt=u(f,n.lens,0,n.nlen,n.lencode
,0,n.work,Ct),n.lenbits=Ct.bits;if(Tt){e.msg="invalid literal/lengths set",n.mode=
G;break}n.distbits=6,n.distcode=n.distdyn,Ct={bits:n.distbits},Tt=u(l,n.lens,n.nlen
,n.ndist,n.distcode,0,n.work,Ct),n.distbits=Ct.bits;if(Tt){e.msg="invalid distances set"
,n.mode=G;break}n.mode=R;if(t===p)break e;case R:n.mode=U;case U:if(st>=6&&ot>=258
){e.next_out=rt,e.avail_out=ot,e.next_in=nt,e.avail_in=st,n.hold=ut,n.bits=at,o(
e,lt),rt=e.next_out,tt=e.output,ot=e.avail_out,nt=e.next_in,et=e.input,st=e.avail_in
,ut=n.hold,at=n.bits,n.mode===D&&(n.back=-1);break}n.back=0;for(;;){mt=n.lencode
[ut&(1<<n.lenbits)-1],gt=mt>>>24,yt=mt>>>16&255,bt=mt&65535;if(gt<=at)break;if(st===0
)break e;st--,ut+=et[nt++]<<at,at+=8}if(yt&&(yt&240)===0){wt=gt,Et=yt,St=bt;for(
;;){mt=n.lencode[St+((ut&(1<<wt+Et)-1)>>wt)],gt=mt>>>24,yt=mt>>>16&255,bt=mt&65535
;if(wt+gt<=at)break;if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}ut>>>=wt,at-=wt
,n.back+=wt}ut>>>=gt,at-=gt,n.back+=gt,n.length=bt;if(yt===0){n.mode=$;break}if(
yt&32){n.back=-1,n.mode=D;break}if(yt&64){e.msg="invalid literal/length code",n.
mode=G;break}n.extra=yt&15,n.mode=z;case z:if(n.extra){kt=n.extra;while(at<kt){if(
st===0)break e;st--,ut+=et[nt++]<<at,at+=8}n.length+=ut&(1<<n.extra)-1,ut>>>=n.extra
,at-=n.extra,n.back+=n.extra}n.was=n.length,n.mode=W;case W:for(;;){mt=n.distcode
[ut&(1<<n.distbits)-1],gt=mt>>>24,yt=mt>>>16&255,bt=mt&65535;if(gt<=at)break;if(
st===0)break e;st--,ut+=et[nt++]<<at,at+=8}if((yt&240)===0){wt=gt,Et=yt,St=bt;for(
;;){mt=n.distcode[St+((ut&(1<<wt+Et)-1)>>wt)],gt=mt>>>24,yt=mt>>>16&255,bt=mt&65535
;if(wt+gt<=at)break;if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}ut>>>=wt,at-=wt
,n.back+=wt}ut>>>=gt,at-=gt,n.back+=gt;if(yt&64){e.msg="invalid distance code",n
.mode=G;break}n.offset=bt,n.extra=yt&15,n.mode=X;case X:if(n.extra){kt=n.extra;while(
at<kt){if(st===0)break e;st--,ut+=et[nt++]<<at,at+=8}n.offset+=ut&(1<<n.extra)-1
,ut>>>=n.extra,at-=n.extra,n.back+=n.extra}if(n.offset>n.dmax){e.msg="invalid distance too far back"
,n.mode=G;break}n.mode=V;case V:if(ot===0)break e;ct=lt-ot;if(n.offset>ct){ct=n.
offset-ct;if(ct>n.whave&&n.sane){e.msg="invalid distance too far back",n.mode=G;
break}ct>n.wnext?(ct-=n.wnext,ht=n.wsize-ct):ht=n.wnext-ct,ct>n.length&&(ct=n.length
),pt=n.window}else pt=tt,ht=rt-n.offset,ct=n.length;ct>ot&&(ct=ot),ot-=ct,n.length-=
ct;do tt[rt++]=pt[ht++];while(--ct);n.length===0&&(n.mode=U);break;case $:if(ot===0
)break e;tt[rt++]=n.length,ot--,n.mode=U;break;case J:if(n.wrap){while(at<32){if(
st===0)break e;st--,ut|=et[nt++]<<at,at+=8}lt-=ot,e.total_out+=lt,n.total+=lt,lt&&
(e.adler=n.check=n.flags?s(n.check,tt,lt,rt-lt):i(n.check,tt,lt,rt-lt)),lt=ot;if(
(n.flags?ut:it(ut))!==n.check){e.msg="incorrect data check",n.mode=G;break}ut=0,
at=0}n.mode=K;case K:if(n.wrap&&n.flags){while(at<32){if(st===0)break e;st--,ut+=
et[nt++]<<at,at+=8}if(ut!==(n.total&4294967295)){e.msg="incorrect length check",
n.mode=G;break}ut=0,at=0}n.mode=Q;case Q:Tt=v;break e;case G:Tt=y;break e;case Y
:return b;case Z:default:return g}e.next_out=rt,e.avail_out=ot,e.next_in=nt,e.avail_in=
st,n.hold=ut,n.bits=at;if(n.wsize||lt!==e.avail_out&&n.mode<G&&(n.mode<J||t!==c)
)if(vt(e,e.output,e.next_out,lt-e.avail_out))return n.mode=Y,b;return ft-=e.avail_in
,lt-=e.avail_out,e.total_in+=ft,e.total_out+=lt,n.total+=lt,n.wrap&&lt&&(e.adler=
n.check=n.flags?s(n.check,tt,lt,e.next_out-lt):i(n.check,tt,lt,e.next_out-lt)),e
.data_type=n.bits+(n.last?64:0)+(n.mode===D?128:0)+(n.mode===R||n.mode===B?256:0
),(ft===0&&lt===0||t===c)&&Tt===d&&(Tt=w),Tt}function gt(e){if(!e||!e.state)return g
;var t=e.state;return t.window&&(t.window=null),e.state=null,d}function yt(e,t){
var n;return!e||!e.state?g:(n=e.state,(n.wrap&2)===0?g:(n.head=t,t.done=!1,d))}function bt
(e,t){var n=t.length,r,s,o;if(!e||!e.state)return g;r=e.state;if(r.wrap!==0&&r.mode!==
_)return g;if(r.mode===_){s=1,s=i(s,t,n,0);if(s!==r.check)return y}return o=vt(e
,t,n,n),o?(r.mode=Y,b):(r.havedict=1,d)}var r=e("../utils/common"),i=e("./adler32"
),s=e("./crc32"),o=e("./inffast"),u=e("./inftrees"),a=0,f=1,l=2,c=4,h=5,p=6,d=0,
v=1,m=2,g=-2,y=-3,b=-4,w=-5,E=8,S=1,x=2,T=3,N=4,C=5,k=6,L=7,A=8,O=9,M=10,_=11,D=12
,P=13,H=14,B=15,j=16,F=17,I=18,q=19,R=20,U=21,z=22,W=23,X=24,V=25,$=26,J=27,K=28
,Q=29,G=30,Y=31,Z=32,et=852,tt=592,nt=15,rt=nt,ct=!0,ht,pt;n.inflateReset=ut,n.inflateReset2=
at,n.inflateResetKeep=ot,n.inflateInit=lt,n.inflateInit2=ft,n.inflate=mt,n.inflateEnd=
gt,n.inflateGetHeader=yt,n.inflateSetDictionary=bt,n.inflateInfo="pako inflate (from Nodeca project)"
},{"../utils/common":1,"./adler32":3,"./crc32":5,"./inffast":7,"./inftrees":9}],9
:[function(e,t,n){"use strict";var r=e("../utils/common"),i=15,s=852,o=592,u=0,a=1
,f=2,l=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163
,195,227,258,0,0],c=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19
,20,20,20,20,21,21,21,21,16,72,78],h=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193
,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],p=[16
,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28
,29,29,64,64];t.exports=function(t,n,d,v,m,g,y,b){var w=b.bits,E=0,S=0,x=0,T=0,N=0
,C=0,k=0,L=0,A=0,O=0,M,_,D,P,H,B=null,j=0,F,I=new r.Buf16(i+1),q=new r.Buf16(i+1
),R=null,U=0,z,W,X;for(E=0;E<=i;E++)I[E]=0;for(S=0;S<v;S++)I[n[d+S]]++;N=w;for(T=
i;T>=1;T--)if(I[T]!==0)break;N>T&&(N=T);if(T===0)return m[g++]=20971520,m[g++]=20971520
,b.bits=1,0;for(x=1;x<T;x++)if(I[x]!==0)break;N<x&&(N=x),L=1;for(E=1;E<=i;E++){L<<=1
,L-=I[E];if(L<0)return-1}if(L>0&&(t===u||T!==1))return-1;q[1]=0;for(E=1;E<i;E++)
q[E+1]=q[E]+I[E];for(S=0;S<v;S++)n[d+S]!==0&&(y[q[n[d+S]]++]=S);t===u?(B=R=y,F=19
):t===a?(B=l,j-=257,R=c,U-=257,F=256):(B=h,R=p,F=-1),O=0,S=0,E=x,H=g,C=N,k=0,D=-1
,A=1<<N,P=A-1;if(t===a&&A>s||t===f&&A>o)return 1;for(;;){z=E-k,y[S]<F?(W=0,X=y[S
]):y[S]>F?(W=R[U+y[S]],X=B[j+y[S]]):(W=96,X=0),M=1<<E-k,_=1<<C,x=_;do _-=M,m[H+(
O>>k)+_]=z<<24|W<<16|X|0;while(_!==0);M=1<<E-1;while(O&M)M>>=1;M!==0?(O&=M-1,O+=
M):O=0,S++;if(--I[E]===0){if(E===T)break;E=n[d+y[S]]}if(E>N&&(O&P)!==D){k===0&&(
k=N),H+=x,C=E-k,L=1<<C;while(C+k<T){L-=I[C+k];if(L<=0)break;C++,L<<=1}A+=1<<C;if(
t===a&&A>s||t===f&&A>o)return 1;D=O&P,m[D]=N<<24|C<<16|H-g|0}}return O!==0&&(m[H+
O]=E-k<<24|64<<16|0),b.bits=N,0}},{"../utils/common":1}],10:[function(e,t,n){"use strict"
;t.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error"
,"-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"
}},{}],11:[function(e,t,n){"use strict";function r(){this.input=null,this.next_in=0
,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0
,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}t.exports=
r},{}],"/lib/inflate.js":[function(e,t,n){"use strict";function c(e){if(!(this instanceof 
c))return new c(e);this.options=i.assign({chunkSize:16384,windowBits:0,to:""},e||
{});var t=this.options;t.raw&&t.windowBits>=0&&t.windowBits<16&&(t.windowBits=-t
.windowBits,t.windowBits===0&&(t.windowBits=-15)),t.windowBits>=0&&t.windowBits<16&&
(!e||!e.windowBits)&&(t.windowBits+=32),t.windowBits>15&&t.windowBits<48&&(t.windowBits&15
)===0&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this
.strm=new a,this.strm.avail_out=0;var n=r.inflateInit2(this.strm,t.windowBits);if(
n!==o.Z_OK)throw new Error(u[n]);this.header=new f,r.inflateGetHeader(this.strm,
this.header);if(t.dictionary){typeof t.dictionary=="string"?t.dictionary=s.string2buf
(t.dictionary):l.call(t.dictionary)==="[object ArrayBuffer]"&&(t.dictionary=new 
Uint8Array(t.dictionary));if(t.raw){n=r.inflateSetDictionary(this.strm,t.dictionary
);if(n!==o.Z_OK)throw new Error(u[n])}}}function h(e,t){var n=new c(t);n.push(e,!0
);if(n.err)throw n.msg||u[n.err];return n.result}function p(e,t){return t=t||{},
t.raw=!0,h(e,t)}var r=e("./zlib/inflate"),i=e("./utils/common"),s=e("./utils/strings"
),o=e("./zlib/constants"),u=e("./zlib/messages"),a=e("./zlib/zstream"),f=e("./zlib/gzheader"
),l=Object.prototype.toString;c.prototype.push=function(e,t){var n=this.strm,u=this
.options.chunkSize,a=this.options.dictionary,f,c,h,p,d,v=!1;if(this.ended)return!1
;c=t===~~t?t:t===!0?o.Z_FINISH:o.Z_NO_FLUSH,typeof e=="string"?n.input=s.binstring2buf
(e):l.call(e)==="[object ArrayBuffer]"?n.input=new Uint8Array(e):n.input=e,n.next_in=0
,n.avail_in=n.input.length;do{n.avail_out===0&&(n.output=new i.Buf8(u),n.next_out=0
,n.avail_out=u),f=r.inflate(n,o.Z_NO_FLUSH),f===o.Z_NEED_DICT&&a&&(f=r.inflateSetDictionary
(this.strm,a)),f===o.Z_BUF_ERROR&&v===!0&&(f=o.Z_OK,v=!1);if(f!==o.Z_STREAM_END&&
f!==o.Z_OK)return this.onEnd(f),this.ended=!0,!1;n.next_out&&(n.avail_out===0||f===
o.Z_STREAM_END||n.avail_in===0&&(c===o.Z_FINISH||c===o.Z_SYNC_FLUSH))&&(this.options
.to==="string"?(h=s.utf8border(n.output,n.next_out),p=n.next_out-h,d=s.buf2string
(n.output,h),n.next_out=p,n.avail_out=u-p,p&&i.arraySet(n.output,n.output,h,p,0)
,this.onData(d)):this.onData(i.shrinkBuf(n.output,n.next_out))),n.avail_in===0&&
n.avail_out===0&&(v=!0)}while((n.avail_in>0||n.avail_out===0)&&f!==o.Z_STREAM_END
);return f===o.Z_STREAM_END&&(c=o.Z_FINISH),c===o.Z_FINISH?(f=r.inflateEnd(this.
strm),this.onEnd(f),this.ended=!0,f===o.Z_OK):c===o.Z_SYNC_FLUSH?(this.onEnd(o.Z_OK
),n.avail_out=0,!0):!0},c.prototype.onData=function(e){this.chunks.push(e)},c.prototype
.onEnd=function(e){e===o.Z_OK&&(this.options.to==="string"?this.result=this.chunks
.join(""):this.result=i.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this
.msg=this.strm.msg},n.Inflate=c,n.inflate=h,n.inflateRaw=p,n.ungzip=h},{"./utils/common"
:1,"./utils/strings":2,"./zlib/constants":4,"./zlib/gzheader":6,"./zlib/inflate"
:8,"./zlib/messages":10,"./zlib/zstream":11}]},{},[])("/lib/inflate.js")})

</script>

    <script type="text/javascript">
var compressedModel = "eJzVV02PmzAQ/SvI10Tpbo8r5ZSuqpVWqVSpvUQRcsBhXRkb2SYkXeW/18OHYxNI2A2H9AaDZ5j3Zt4MvCMtCUFPwTviOIULJIXQaBogfci8+4hhpcDwXYo8AwvZZ5IoRQUHO88Zg2MizQQnXId1gNqu8o06KE3Sxo6SJg5VYYYlZowwY99ipoixMsoJlqESbEcknH9dPgU/fy1/LBfP4MUFPzuyfPWORG+UxZJw82h1AhgTRRMe7rBULk6boAf2hcck+43lwsDqxXyOzbLQj++MKEThXagLeh/efpD7EBMpXHwi11le5ZNmjEZUO8nEzSkeYynxAR2ngRtMaZlH+oZway8g5FaFDKNDxMj1OvzvTdeuRjfK5z2JujtthYpgHuSTU10XbO7dxvA8mAS1aT1eXxKT1UhtmbscUF530LXua5M30HERj9T/CzZSoGI0BZ0L8uMdlZuOKSauuFPjNbeG+2yh4lMtdM7XQFegZKTq5zdV36+/2Pwhkaa7AaPzUgts54BvsmBfjFjus96+iodKn41Q6oFu29FEHZmyaIkpv1HYydzgv9NqfqYwyc3CQYYGg1W/QUgVMqp0yVT7Q2R2mhNnj+xaNWXiID5Dt430jpSMuj5t6ogz21yJ9vRbPSjhXomQO+6dyVUnyvvQoBdF2Q2rx2nwsF5ffEPpXQutnZ8xD/Bl3b7so74nCQxzLi6RUhNXdNLyMA0efVqcH4OZ89FxifH6WH8UZ+9cTtIePUKL4Y36mkmRIvgzq1QCV31lb5bLxSS9T6l+rpoVezXR1l71OsbOba8XrP5b3e/MXr/+lQPot1Y9kNBRJg9aZwFayfYqwCbe26sWRF9DXiOwDblf701ZT3Rt7cJxiEqqGXkEnmJJqxl8mp7fKpM7QjNNU/oXwwgr42e63h3A7iZPwkzCEjIyKYeneR4qojXlSfPTdfSJBlcwmTVkdoci1hATs7EkgT2jqRnSdmCu/fcej/8A+65xGA==";
</script>
     <script type="text/javascript">
///////////////////////////
//Modal Help Dialog Stuff
///////////////////////////
var parentDiv = document.getElementById("ptN2ContentDivId");
var modal = parentDiv.querySelector("#myModal");

// When the user clicks the button, open the modal
function DisplayModal() {
    modal.style.display = "block";
}

// When the user clicks on <span> (x), close the modal
parentDiv.querySelector("#idSpanModalClose").onclick = function() {
    modal.style.display = "none";
}

// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
    if (event.target == modal) {
        modal.style.display = "none";
    }
}

</script>

    <script type="text/javascript">
/** A faster way to find an object in an array than indexOf.
 * @param {array} arr The array to search.
 * @param {Object} obj The object to search for.
 * @returns The index of the first matching object, or -1 if not found.
 */
function indexFor(arr, obj) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === obj) {
            return i;
        }
    }

    return -1;
}

/** Find the index of an object in the array with the first member
 * that matches the supplied value.
 * @param {any[]} arr The array to search.
 * @param {string} memName The name of the object member.
 * @param {Object} val The value of the object member to match.
 * @returns The index of the first matching object or -1 if not found.
 */
function indexForMember(arr, memName, val) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i].hasOwnProperty(memName) &&
            arr[i][memName] === val) {
            return i;
        }
    }

    return -1;
}

/** Make sure testVar is neither undefined or null.
 * @param {any} testVar The variable to check.
 * @return {Boolean} True if testVar is not undefined and not null.
*/
function exists(testVar) {
    return (testVar !== undefined && testVar !== null);
}

/**
 * Add a method to the Object prototype call propExists(),
 * which is stronger than hasOwnProperty() in that it also checks
 * the property for undefined and null values.
 * @param {string} propName The name of the property to check.
 * @return {Boolean} True if propName exists in the object, and is
 *   not undefined and not null.
 */
Object.defineProperty(Object.prototype, 'propExists', {
    value: function (propName) {
        return (this.hasOwnProperty(propName) &&
            this[propName] !== undefined &&
            this[propName] !== null);
    },
    enumerable: false,
});

/**
 * Since checking for an Array's existance as well as 
 * length > 0 is very common, combine the two.
 */
Array.isPopulatedArray = function (arr) {
    return (Array.isArray(arr) && arr.length > 0);
};

const inputRegex = /^(input|unconnected_input|autoivc_input)$/;
const inputOrOutputRegex = /^(output|input|unconnected_input|autoivc_input)$/;

d3.selection.prototype.originalFuncs = {
    'transition': d3.selection.prototype.transition,
    'duration': d3.selection.prototype.duration,
    'delay': d3.selection.prototype.delay
};
d3.selection.prototype.transitionAllowed = true;

function returnThis() { return this; }

function startTimer(label) {
    if (DebugFlags.timings) console.time(label);
}

function stopTimer(label) {
    if (DebugFlags.timings) console.timeEnd(label);
}

function debugInfo() {
    if (DebugFlags.info) console.log(...arguments);
}

/**
 * When class member functions are used with callbacks, 'this' can be redefined if
 * not managed carefully. This function double checks to make sure 'this' refers
 * to the correct class.
 * @param {Object} testThis The 'this' from inside the calling member function.
 * @param {string} className The name of the expected class.
 * @param {string} funcName The name of the calling function, for error reporting.
 * @throws {TypeError} If testThis isn't an instance of className.
 */
function testThis(testThis, className, funcName) {
    let thisClass = testThis.constructor.name;

    if (thisClass != className) {
        throw new TypeError(className + '.' + funcName +
            ": 'this' is an instance of '" + thisClass +
            "'; expected '" + className + "'.");
    }

    // console.log(className + '.' + funcName + ": 'this' IS an instance of the " + className + " class.");
}

</script>
     <script type="text/javascript">
/**
 * @typedef {Object} SymbolType
 * @property {string} name What the symbol is called.
 * @property {Boolean} declaredPartial Whether the symbol is a declared partial.
 */
class SymbolType {

    /**
     * Determine the name and whether it's a declared partial based on info
     * from the provided node.
     * @param {N2MatrixCell} cell The object to select the type from.
     * @param {ModelData} model Reference to the model to get some info from it.
     */
    constructor(cell, model) {
        this.name = null;

        // Indicates that the type of symbol CAN be a declared partial
        // AND both source and target objects are part of the same component.
        this.potentialDeclaredPartial = false;

        this.declaredPartial = false;

        // Update properties based on the the referenced node.
        this.getType(cell, model);
    }

    /**
     * For symbols types that CAN be a declared partial, check whether they're
     * part of the same component and that they're in the declared partial list.
     * @param {N2TreeNode} cell The cell to operate on.
     * @param {ModelData} model Reference to the entire model.
     */
    _setDeclaredPartialInfo(cell, model) {
        if (cell.tgtObj.parentComponent === cell.srcObj.parentComponent) {
            this.potentialDeclaredPartial = true;
            this.declaredPartial = model.isDeclaredPartial(cell.srcObj, cell.tgtObj);
        }
    }

    /** 
     * Decide what object the cell will be drawn as, based on its position
     * in the matrix, type, source, target, and/or other conditions.
     * @param {N2MatrixCell} cell The cell to operate on.
     * @param {ModelData} model Reference to the entire model.
     */
    getType(cell, model) {
        if (cell.onDiagonal()) {
            if (cell.srcObj.isSubsystem()) this.name = 'group';
            else if (cell.srcObj.isInputOrOutput()) {
                if (cell.srcObj.dtype == "ndarray") this.name = 'vector';
                else this.name = 'scalar';
            }
            else {
                throw ("Output symbol type '" + cell.srcObj.type + "' for cell on diagonal.");
            }
        }
        else if (cell.srcObj.isSubsystem()) {
            if (cell.tgtObj.isSubsystem()) this.name = 'groupGroup';
            else if (cell.tgtObj.isInputOrOutput()) {
                if (cell.tgtObj.dtype == "ndarray") this.name = 'groupVector';
                else this.name = 'groupScalar';
            }
            else throw ("Output group symbol type.");
        }
        else if (cell.srcObj.isInputOrOutput()) {
            if (cell.srcObj.dtype == "ndarray") {
                if (cell.tgtObj.isInputOrOutput()) {
                    if (cell.tgtObj.dtype == "ndarray" || cell.tgtObj.isInput()) {
                        this.name = 'vectorVector';
                        this._setDeclaredPartialInfo(cell, model);
                    }
                    else {
                        this.name = 'vectorScalar';
                        this._setDeclaredPartialInfo(cell, model);
                    }
                }

                else if (cell.tgtObj.isSubsystem()) this.name = 'vectorGroup';
                else throw ("Output vector symbol type.");
            }

            else if (cell.tgtObj.isInputOrOutput()) {
                if (cell.tgtObj.dtype == "ndarray") {
                    this.name = 'scalarVector';
                    this._setDeclaredPartialInfo(cell, model);
                }
                else {
                    this.name = 'scalarScalar';
                    this._setDeclaredPartialInfo(cell, model);
                }
            }

            else if (cell.tgtObj.isSubsystem()) this.name = 'scalarGroup';

            else throw ("Output vector or scalar symbol type.");
        }
        else throw ("Completely unrecognized symbol type.")
    }
}

</script>
     <script type="text/javascript">
/**
 * Essentially the same as a JSON object from the model tree,
 * with some utility functions.
 * @typedef {N2TreeNode}
 * @property {Object} dims The size and location of the node when drawn.
 * @property {Object} prevDims The previous value of dims.
 * @property {Object} solverDims The size and location of the node within the solver tree.
 * @property {Object} prevSolverDims The previous value of solverDims.
 * @property {Boolean} isMinimized Whether this node or a parent has been collapsed.
 * @property {Number} nameWidthPx The width of the name in pixels as computed by N2Layout.
 * @property {Boolean} manuallyExpanded If this node was right-clicked.
 * @property {Number} depth The index of the column this node appears in.
 */
class N2TreeNode {

    /**
     * Absorb all the properties of the provided JSON object from the model tree.
     * @param {Object} origNode The node to work from.
     */
    constructor(origNode) {
        // Merge all of the props from the original JSON tree node to us.
        Object.assign(this, origNode);

        this.sourceParentSet = new Set();
        this.targetParentSet = new Set();
        this.nameWidthPx = 1; // Set by N2Layout
        this.numLeaves = 0; // Set by N2Layout
        this.isMinimized = false;
        this.manuallyExpanded = false;
        this.childNames = new Set(); // Set by ModelData
        this.depth = -1; // Set by ModelData
        this.parent = null; // Set by ModelData
        this.id = -1; // Set by ModelData
        this.absPathName = ''; // Set by ModelData
        this.numDescendants = 0; // Set by ModelData

        // Solver names may be empty, so set them to "None" instead.
        if (this.linear_solver == "") this.linear_solver = "None";
        if (this.nonlinear_solver == "") this.nonlinear_solver = "None";

        this.rootIndex = -1;
        this.dims = {
            'x': 1e-6,
            'y': 1e-6,
            'width': 1,
            'height': 1
        };
        this.prevDims = {
            'x': 1e-6,
            'y': 1e-6,
            'width': 1e-6,
            'height': 1e-6
        };
        this.solverDims = {
            'x': 1e-6,
            'y': 1e-6,
            'width': 1,
            'height': 1
        };
        this.prevSolverDims = {
            'x': 1e-6,
            'y': 1e-6,
            'width': 1e-6,
            'height': 1e-6
        };

    }

    /** Run when a node is collapsed. */
    minimize() {
        this.isMinimized = true;
    }

    /** Run when a node is restored. */
    expand() {
        this.isMinimized = false;
    }

    /**
     * Create a backup of our position and other info.
     * @param {boolean} solver Whether to use .dims or .solverDims.
     * @param {number} leafNum Identify this as the nth leaf of the tree
     */
    preserveDims(solver, leafNum) {
        let dimProp = solver ? 'dims' : 'solverDims';
        let prevDimProp = solver ? 'prevDims' : 'prevSolverDims';

        Object.assign(this[prevDimProp], this[dimProp]);

        if (this.rootIndex < 0) this.rootIndex = leafNum;
        this.prevRootIndex = this.rootIndex;
    }

    /** 
     * Determine if the children array exists and has members.
     * @param {string} [childrenPropName = 'children'] Usually children, but
     *   sometimes 'subsystem_children'
     * @return {boolean} True if the children property is an Array and length > 0.
     */
    hasChildren(childrenPropName = 'children') {
        return (Array.isPopulatedArray(this[childrenPropName]));
    }

    /** True if this.type is 'input' or 'unconnected_input'. */
    isInput() {
        return this.type.match(inputRegex);
    }

    /** True if this is an input and connected. */
    isConnectedInput() { return (this.type == 'input'); }

    /** True if this an input and unconnected. */
    isUnconnectedInput() { return (this.type == 'unconnected_input'); }

    /** True if this is an input whose source is an auto-ivc'd output */
    isAutoIvcInput() { return (this.type == 'autoivc_input');}

    /** True if this.type is 'output'. */
    isOutput() { return (this.type == 'output'); }

    /** True if this is the root node in the model */
    isRoot() { return (this.type == 'root'); }

    /** True if this is an output and it's not implicit */
    isExplicitOutput() { return (this.isOutput() && !this.implicit); }

    /** True if this is an output and it is implicit */
    isImplicitOutput() { return (this.isOutput() && this.implicit); }

    /** True if this.type is 'input', 'unconnected_input', or 'output'. */
    isInputOrOutput() { return this.type.match(inputOrOutputRegex); }

    /** True is this.type is 'subsystem' */
    isSubsystem() { return (this.type == 'subsystem'); }

    /** True if it's a subsystem and this.subsystem_type is 'group' */
    isGroup() { return ( this.isSubsystem() && this.subsystem_type == 'group'); }

    /** True if it's a subsystem and this.subsystem_type is 'component' */
    isComponent() { return ( this.isSubsystem() && this.subsystem_type == 'component'); }

    /** Not connectable if this is a input group or parents are minimized. */
    isConnectable() {
        if (this.isInputOrOutput() && !(this.hasChildren() ||
                this.parent.isMinimized || this.parentComponent.isMinimized)) return true;

        return this.isMinimized;
    }

    /** Return false if the node is minimized or hidden */
    isVisible() {
        return ! (this.varIsHidden || this.isMinimized);
    }

    /**
     * Look for the supplied node in the set of child names.
     * @returns {Boolean} True if a match is found, otherwise false.
     */
    hasNodeInChildren(compareNode) {
        return this.childNames.has(compareNode.absPathName);
    }

    /** Look for the supplied node in the parentage of this one.
     * @param {N2TreeNode} compareNode The node to look for.
     * @param {N2TreeNode} [parentLimit = null] Stop searching at this common parent.
     * @returns {Boolean} True if the node is found, otherwise false.
     */
    hasParent(compareNode, parentLimit = null) {
        for (let obj = this.parent; obj != null && obj !== parentLimit; obj = obj.parent) {
            if (obj === compareNode) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * Look for the supplied node in the lineage of this one.
     * @param {N2TreeNode} compareNode The node to look for.
     * @param {N2TreeNode} [parentLimit = null] Stop searching at this common parent.
     * @returns {Boolean} True if the node is found, otherwise false.
     */
    hasNode(compareNode, parentLimit = null) {
        if (this.type == 'root') return true;

        if ( this === compareNode) return true;

        // Check parents first.
        if (this.hasParent(compareNode, parentLimit)) return true;

        return this.hasNodeInChildren(compareNode);
    }

    /**
     * Add ourselves to the supplied array if we contain a cycleArrows property.
     * @param {Array} arr The array to add to.
     */
    _getNodesInChildrenWithCycleArrows(arr) {
        if (this.cycleArrows) {
            arr.push(this);
        }

        if (this.hasChildren()) {
            for (let child of this.children) {
                child._getNodesInChildrenWithCycleArrows(arr);
            }
        }
    }

    /**
     * Populate an array with nodes in our lineage that contain a cycleArrows member.
     * @returns {Array} The array containing all the found nodes with cycleArrows.
     */
    getNodesWithCycleArrows() {
        let arr = [];

        // Check parents first.
        for (let obj = this.parent; obj != null; obj = obj.parent) {
            if (obj.cycleArrows) {
                arr.push(obj);
            }
        }

        // Check all descendants as well.
        this._getNodesInChildrenWithCycleArrows(arr);

        return arr;
    }

    /**
     * Find the closest parent shared by two nodes; farthest should be tree root.
     * @param {N2TreeNode} other Another node to compare parents with.
     * @returns {N2TreeNode} The first common parent found.
     */
    nearestCommonParent(other) {
        for (let myParent = this.parent; myParent != null; myParent = myParent.parent)
            for (let otherParent = other.parent; otherParent != null; otherParent = otherParent.parent)
                if (myParent === otherParent) return myParent;

        // Should never get here because root is parent of all
        debugInfo("No common parent found between two nodes: ", this, other);
        return null;
    }

    /**
     * If the node has a lot of descendants and it wasn't manually expanded,
     * minimize it.
     * @returns {Boolean} True if minimized here, false otherwise.
     */
    minimizeIfLarge() {
        if ( ! (this.isRoot() || this.manuallyExpanded) &&
            (this.numDescendants > PRECOLLAPSE_THRESHOLD &&
                this.children.length > 1 ) ) {
            debugInfo(`Precollapsing node ${this.absPathName}`)
            this.minimize();
            return true;
        }

        return false;
    }
}

</script>
     <script type="text/javascript">
/** Process the tree, connections, and other info provided about the model. */
class ModelData {

    /** Do some discovery in the tree and rearrange & enhance where necessary. */
    constructor(modelJSON) {

        modelJSON.tree.name = 'model'; // Change 'root' to 'model'
        this.conns = modelJSON.connections_list;
        this.abs2prom = modelJSON.abs2prom; // May be undefined.
        this.declarePartialsList = modelJSON.declare_partials_list;
        this.useDeclarePartialsList = (this.declarePartialsList.length > 0);
        this.sysPathnamesList = modelJSON.sys_pathnames_list;

        this.maxDepth = 1;
        this.unconnectedInputs = 0;
        this.autoivcSources = 0;
        this.nodePaths = {};
        this.nodeIds = [];

        startTimer('ModelData._convertToN2TreeNodes');
        this.root = this.tree = modelJSON.tree = this._convertToN2TreeNodes(modelJSON.tree);
        stopTimer('ModelData._convertToN2TreeNodes');

        startTimer('ModelData._setParentsAndDepth');
        this._setParentsAndDepth(this.root, null, 1);
        stopTimer('ModelData._setParentsAndDepth');

        if (this.unconnectedInputs > 0)
            console.info("Unconnected nodes: ", this.unconnectedInputs);

        startTimer('ModelData._initSubSystemChildren');
        this._initSubSystemChildren(this.root);
        stopTimer('ModelData._initSubSystemChildren');

        startTimer('ModelData._computeConnections');
        this._computeConnections();
        stopTimer('ModelData._computeConnections');

        debugInfo("New model: ", this);
        // this.errorCheck();
    }

    static uncompressModel(b64str) {
        const compressedData = atob(b64str);
        const jsonStr = window.pako.inflate(compressedData, { to: 'string' });
        return JSON.parse(jsonStr);
    }

    /**
     * For debugging: Make sure every tree member is an N2TreeNode.
     * @param {N2TreeNode} [node = this.root] The node to start with.
     */
    errorCheck(node = this.root) {
        if (!(node instanceof N2TreeNode))
            debugInfo('Node with problem: ', node);

        for (let prop of ['parent', 'originalParent', 'parentComponent']) {
            if (node[prop] && !(node[prop] instanceof N2TreeNode))
                debugInfo('Node with problem ' + prop + ': ', node);
        }

        if (node.hasChildren()) {
            for (let child of node.children) {
                this.errorCheck(child);
            }
        }
    }

    /**
     * Recurse over the tree and replace the JSON objects 
     * provided by n2_viewer.py with N2TreeNodes.
     * @param {Object} element The current element being updated.
     */
    _convertToN2TreeNodes(element) {
        let newNode = new N2TreeNode(element);

        if (newNode.hasChildren()) {
            for (let i in newNode.children) {
                newNode.children[i] = this._convertToN2TreeNodes(newNode.children[i]);
                newNode.children[i].parent = newNode;
                if (exists(newNode.children[i].parentComponent))
                    newNode.children[i].parentComponent = newNode;
            }
        }

        return newNode;
    }

    /**
     * Sets parents and depth of all nodes, and determine max depth. Flags the
     * node as implicit if any children are implicit.
     * @param {N2TreeNode} node Item to process.
     * @param {N2TreeNode} parent Parent of node, null for root node.
     * @param {number} depth Numerical level of ancestry.
     * @return True is node is implicit, false otherwise.
     */
    _setParentsAndDepth(node, parent, depth) { // Formerly InitTree()
        node.depth = depth;
        node.parent = parent;
        node.id = this.nodeIds.length;
        this.nodeIds.push(node);

        if (node.parent) { // not root node? node.parent.absPathName : "";
            if (node.parent.absPathName != "") {
                node.absPathName += node.parent.absPathName + ".";
            }

            node.absPathName += node.name;

            this.nodePaths[node.absPathName] = node;
        }

        this.identifyUnconnectedInput(node);

        if (node.isInputOrOutput()) {
            let parentComponent = (node.originalParent) ? node.originalParent : node.parent;
            if (parentComponent.type == "subsystem" &&
                parentComponent.subsystem_type == "component") {
                node.parentComponent = parentComponent;
            }
            else {
                throw ("Input or output without a parent component!");
            }
        }

        this.maxDepth = Math.max(depth, this.maxDepth);

        if (node.isSubsystem()) {
            this.maxSystemDepth = Math.max(depth, this.maxSystemDepth);
        }

        node.childNames.add(node.absPathName); // Add the node itself

        if (node.hasChildren()) {
            node.numDescendants = node.children.length;
            for (let child of node.children) {

                let implicit = this._setParentsAndDepth(child, node, depth + 1);
                if (implicit) node.implicit = true;

                node.numDescendants += child.numDescendants;

                // Add absolute pathnames of children to a set for quick searching
                if (!node.isRoot()) { // All nodes are children of the model root 
                    node.childNames.add(child.absPathName);
                    for (let childName of child.childNames) {
                        node.childNames.add(childName);
                    }
                }
            }
        }

        return (node.implicit) ? true : false;
    }

    /**
     * Check the entire array of model connections for any with a target matching
     * the specified path.
     * @param {string} elementPath The full path of the element to check.
     * @return True if the path is found as a target in the connection list.
     */
    hasInputConnection(elementPath) {
        for (let conn of this.conns) {
            if (conn.tgt.match(elementPath)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check the entire array of model connections for any with a source matching
     * the specified path.
     * @param {string} elementPath The full path of the element to check.
     * @return True if the path is found as a source in the connection list.
     */
    hasOutputConnection(elementPath) {
        for (let conn of this.conns) {
            if (conn.src.match(elementPath)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check the entire array of model connections for any with a source OR
     * target matching the specified path.
     * @param {string} elementPath The full path of the element to check.
     * @return True if the path is found as a source in the connection list.
     */
    hasAnyConnection(elementPath) {

        for (let conn of this.conns) {
            if (conn.src == elementPath || conn.tgt == elementPath)
                return true;
        }

        debugInfo(elementPath + " has no connections.");
        this.unconnectedInputs++;

        return false;
    }

    hasAutoIvcSrc(elementPath) {
        for (let conn of this.conns) {
            if (conn.tgt == elementPath && conn.src.match(/^_auto_ivc.*$/)) {
                debugInfo(elementPath + " source is an auto-ivc output.");
                this.autoivcSources++;
                return true;
            }
        }

        return false;
    }

    /**
     * Create an array in each node containing references to its
     * children that are subsystems. Runs recursively over the node's
     * children array.
     * @param {N2TreeNode} node Node with children to check.
     */
    _initSubSystemChildren(node) {
        if (!node.hasChildren()) {
            return;
        }

        for (let child of node.children) {
            if (child.isSubsystem()) {
                if (!node.hasChildren('subsystem_children'))
                    node.subsystem_children = [];

                node.subsystem_children.push(child);
                this._initSubSystemChildren(child);
            }
        }
    }

    /**
     * Build a string from the absoluate path names of the two elements and
     * try to find it in the declare partials list.
     * @param {Object} srcObj The source element.
     * @param {Object} tgtObj The target element.
     * @return {Boolean} True if the string was found.
     */
    isDeclaredPartial(srcObj, tgtObj) {
        let partialsStr = tgtObj.absPathName + " > " + srcObj.absPathName;

        return this.declarePartialsList.includes(partialsStr);
    }

    /** 
     * Add all leaf descendents of specified node to the array.
     * @param {N2TreeNode} node Current node to work on.
     * @param {N2TreeNode[]} objArray Array to add to.
     */

    _addLeaves(node, objArray) {
        if (!node.isInput()) {
            objArray.push(node);
        }

        if (node.hasChildren()) {
            for (let child of node.children) {
                this._addLeaves(child, objArray);
            }
        }
    }

    /**
     * Iterate over the connections list, and find the objects that make up
     * each connection, and do some error checking. Store an array containing the
     * target object and all of its parents in the source object and all of *its*
     * parents. In the target object, store an array containing references to
     * the begin and end of all the cycle arrows.
     */
    _computeConnections() {
        let sysPathnames = this.sysPathnamesList;
        let throwLbl = 'ModelData._computeConnections: ';

        for (let conn of this.conns) {
            // Ignore connections from _auto_ivc, which is intentionally not included.
            if (conn.src.match(/^_auto_ivc.*$/)) continue;

            // Process sources
            let srcObj = this.nodePaths[conn.src];

            if (!srcObj) {
                console.warn(throwLbl + "Cannot find connection source " + conn.src);
                continue;
            }

            let srcObjParents = [srcObj];
            if (!srcObj.isOutput()) { // source obj must be output
                console.warn(throwLbl + "Found a source that is not an output.");
                continue;
            }

            if (srcObj.hasChildren()) {
                console.warn(throwLbl + "Found a source that has children.");
                continue;
            }

            for (let obj = srcObj.parent; obj != null; obj = obj.parent) {
                srcObjParents.push(obj);
            }

            // Process targets
            let tgtObj = this.nodePaths[conn.tgt];

            if (!tgtObj) {
                console.warn(throwLbl + "Cannot find connection target " + conn.tgt);
                continue;
            }

            // Target obj must be an input
            if (!tgtObj.isInput()) {
                console.warn(throwLbl + "Found a target that is NOT a input.");
                continue;
            }
            if (tgtObj.hasChildren()) {
                console.warn(throwLbl + "Found a target that has children.");
                continue;
            }

            if (!tgtObj.parentComponent) {
                console.warn(`${throwLbl} Target object ${conn.tgt} is missing a parent component.`);
                continue;
            }

            let tgtObjParents = [tgtObj];
            for (let parentObj = tgtObj.parent; parentObj != null; parentObj = parentObj.parent) {
                tgtObjParents.push(parentObj);
            }

            for (let srcParent of srcObjParents) {
                for (let tgtParent of tgtObjParents) {
                    if (tgtParent.absPathName != "")
                        srcParent.targetParentSet.add(tgtParent);

                    if (srcParent.absPathName != "")
                        tgtParent.sourceParentSet.add(srcParent);
                }
            }

            /*
             * The cycle_arrows object in each connection is an array of length-2 arrays,
             * each of which is an index into the sysPathnames array. Using that array we
             * can resolve the indexes to pathnames to the associated objects.
             */
            if (Array.isPopulatedArray(conn.cycle_arrows)) {
                let cycleArrowsArray = [];
                let cycleArrows = conn.cycle_arrows;
                for (let cycleArrow of cycleArrows) {
                    if (cycleArrow.length != 2) {
                        console.warn(throwLbl + "cycleArrowsSplitArray length not 2, got " +
                            cycleArrow.length + ": " + cycleArrow);
                        continue;
                    }

                    let srcPathname = sysPathnames[cycleArrow[0]];
                    let tgtPathname = sysPathnames[cycleArrow[1]];

                    let arrowBeginObj = this.nodePaths[srcPathname];
                    if (!arrowBeginObj) {
                        console.warn(throwLbl + "Cannot find cycle arrows begin object " + srcPathname);
                        continue;
                    }

                    let arrowEndObj = this.nodePaths[tgtPathname];
                    if (!arrowEndObj) {
                        console.warn(throwLbl + "Cannot find cycle arrows end object " + tgtPathname);
                        continue;
                    }

                    cycleArrowsArray.push({
                        "begin": arrowBeginObj,
                        "end": arrowEndObj
                    });
                }

                if (!tgtObj.parent.hasOwnProperty("cycleArrows")) {
                    tgtObj.parent.cycleArrows = [];
                }
                tgtObj.parent.cycleArrows.push({
                    "src": srcObj,
                    "arrows": cycleArrowsArray
                });
            }
        }
    }

    /**
     * If an element has no connection naming it as a source or target,
     * relabel it as unconnected.
     * @param {N2TreeNode} node The tree node to work on.
     */
    identifyUnconnectedInput(node) { // Formerly updateRootTypes
        if (!node.hasOwnProperty('absPathName')) {
            console.warn("identifyUnconnectedInput error: absPathName not set for ", node);
        }
        else {
            if (node.isInput()) {
                if (!node.hasChildren() && !this.hasAnyConnection(node.absPathName))
                    node.type = "unconnected_input";
                else if (this.hasAutoIvcSrc(node.absPathName))
                    node.type = "autoivc_input";
            }
        }
    }

}

</script>
     <script type="text/javascript">
/**
 * Manage CSS styles for various elements.
 * @typedef N2Style
 */
class N2Style {
    constructor(svgStyle, fontSize) {
        this.svgStyle = svgStyle;

        this.setupSolverStyles();
        this.updateSvgStyle(fontSize);
    }

    /** Make the data in N2Style.solverStyleData more readable */
    setupSolverStyles() {
        this.solvers = {};
        let solverTypes = ['linear', 'nonLinear'];

        for (let sdata of N2Style.solverStyleData) {
            for (let i = 0; i < 2; ++i) {
                if (sdata[i]) {
                    this.solvers[sdata[i]] = {
                        'name': sdata[i],
                        'type': solverTypes[i],
                        'class': 'solver_' +
                            sdata[i]
                                .toLowerCase()
                                .replace(/[: ]/g, '_')
                                .replace(/_+/g, '_'),
                        'style': {
                            'fill': sdata[2],
                            'cursor': 'pointer',
                            'fill-opacity': '.8',
                        },
                    };
                }
            }
        }

        // Object.freeze(this.solvers);
    }

    /**
       * Replace the entire content of the SVG style section with new styles.
       * Doing a wholesale replace is easier than finding each style element,
       * deleting, and inserting a new one.
       * @param {number} fontSize In pixel units.
       */
    updateSvgStyle(fontSize) {
        // Define as JSON first
        let newCssJson = {
            'rect': {
                'stroke': N2Style.color.treeStroke,
            },
            '#tree > g.output > rect': {
                'fill': N2Style.color.outputExplicit,
                'fill-opacity': '.8',
            },
            '#tree > g.output_implicit > rect': {
                'fill': N2Style.color.outputImplicit,
                'fill-opacity': '.8',
            },
            '#tree > g.input > rect': {
                'fill': N2Style.color.input,
                'fill-opacity': '.8',
            },
            '#tree > g.unconnected_input > rect': {
                'fill': N2Style.color.unconnectedInput,
                'fill-opacity': '.8',
            },
            '#tree > g.subsystem > rect': {
                'cursor': 'pointer',
                'fill-opacity': '.8',
                'fill': N2Style.color.group,
            },
            '#tree > g.component > rect': {
                'cursor': 'pointer',
                'fill-opacity': '.8',
                'fill': N2Style.color.component,
            },
            '#tree > g.input_group > rect': {
                'cursor': 'pointer',
                'fill-opacity': '.8',
                'fill': N2Style.color.inputGroup,
            },
            '#tree > g.output_group > rect': {
                'cursor': 'pointer',
                'fill-opacity': '.8',
                'fill': N2Style.color.outputGroup,
            },
            '#tree > g.minimized > rect': {
                'cursor': 'pointer',
                'fill-opacity': '.8',
                'fill': N2Style.color.collapsed,
            },
            '#tree > g.autoivc_input > rect': {
                'cursor': 'pointer',
                'fill-opacity': '.8',
                'fill': N2Style.color.autoivcInput,
            },
            'text': {
                //'dominant-baseline: middle',
                //'dy: .35em',
            },
            '#svgId g.partition_group > text': {
                'text-anchor': 'end',
                'pointer-events': 'none',
                'font-family': 'helvetica, sans-serif',
                'font-size': fontSize + 'px',
            },
            'text.offgridLabel': {
                'font-family': 'helvetica, sans-serif',
                'font-size': fontSize + 'px',
            },
            '#svgId g.solver_group > text': {
                'text-anchor': 'end',
                'pointer-events': 'none',
                'font-family': 'helvetica, sans-serif',
                'font-size': fontSize + 'px',
            },
            'g.component_box > rect': {
                'stroke': N2Style.color.componentBox,
                'stroke-width': '2',
                'fill': 'none',
            },
            '.bordR1, .bordR2, .bordR3, .bordR4, .ssMid, .grpMid, .svMid, .vsMid, .vMid, .sgrpMid, .grpsMid': {
                'stroke': 'none',
                'stroke-width': '0',
                'fill-opacity': '1',
            },
            '[class^=n2_hover_elements]': {
                'pointer-events': 'none',
            },
            '.background': {
                'fill': N2Style.color.background,
            },
            '.horiz_line, .vert_line': {
                'stroke': N2Style.color.gridline,
            },
        };

        for (let solverName in this.solvers) {
            let solver = this.solvers[solverName];

            newCssJson['g.' + solver.class + ' > rect'] = solver.style;
        }

        // Iterate over the JSON object just created and turn it into
        // CSS style sheet text.
        let newCssText = '';
        for (let selector in newCssJson) {
            newCssText += selector + ' {\n';
            for (let attrib in newCssJson[selector]) {
                newCssText +=
                    '    ' + attrib + ': ' + newCssJson[selector][attrib] + ';\n';
            }
            newCssText += '}\n\n';
            if (selector === 'g.subsystem > rect') {
            }
        }

        this.svgStyle.html(newCssText);
    }

    /**
       * Determine the name of the CSS class based on the name of the solver.
       * @param {boolean} showLinearSolverNames Whether to use the linear or non-linear solver name.
       * @param {Object} solverNames
       * @param {string} solverNames.linear The linear solver name.
       * @param {string} solverNames.nonLinear The non-linear solver name.
       * @return {string} The CSS class of the solver, or for "other" if not found.
       */
    getSolverClass(showLinearSolverNames, solverNames) {
        let solverName = showLinearSolverNames
            ? solverNames.linear
            : solverNames.nonLinear;
        return this.solvers[solverName]
            ? this.solvers[solverName].class
            : this.solvers.other.class;
    }

    /**
       * Based on the element's type and conditionally other info, determine
       * what CSS style is associated.
       * @return {string} The name of an existing CSS class.
       */
    getNodeClass(element) {
        if (element.isMinimized) return 'minimized';

        switch (element.type) {
            case 'input':
                if (Array.isPopulatedArray(element.children)) return 'input_group';
                return 'input';

            case 'unconnected_input':
                if (Array.isPopulatedArray(element.children)) return 'input_group';
                return 'unconnected_input';

            case 'autoivc_input':
                return 'autoivc_input';

            case 'output':
                if (Array.isPopulatedArray(element.children)) return 'output_group';
                if (element.implicit) return 'output_implicit';
                return 'output';

            case 'root':
                return 'subsystem';

            case 'subsystem':
                if (element.subsystem_type == 'component') return 'component';
                return 'subsystem';

            default:
                throw 'CSS class not found for element ' + element;
        }
    }
}

// From Isaias Reyes
N2Style.color = {
    'connection': 'gray',
    'outputImplicit': '#C7D06D',
    'outputExplicit': '#9FC4C6',
    'componentBox': '#555',
    'background': '#eee',
    'gridline': 'white',
    'treeStroke': '#eee',
    'outputGroup': '#888',
    'input': '#30B0AD',
    'inputGroup': 'Orchid',
    'group': '#6092B5',
    'component': '#02BFFF',
    'collapsed': '#555555',
    'unconnectedInput': '#F42F0D',
    'inputArrow': 'salmon',
    'outputArrow': 'seagreen',
    'declaredPartial': 'black',
    'autoivcInput': '#F42F0D'
};

Object.freeze(N2Style.color); // Make it the equivalent of a constant

/* 
* This is how we want to map solvers to colors and CSS classes
*    Linear             Nonlinear
*    ---------          ---------
* 0. None               None
* 1. LN: LNBJ           NL: NLBJ
* 2. LN: SCIPY
* 3. LN: RUNONCE        NL: RUNONCE
* 4. LN: Direct
* 5. LN: PETScKrylov
* 6. LN: LNBGS          NL: NLBGS
* 7. LN: USER
* 8.                    NL: Newton
* 9.                    BROYDEN
* 10. solve_linear      solve_nonlinear
* 11. other             other

* Later add these for linesearch ?
* LS: AG
* LS: BCHK
*/
N2Style.solverStyleData = [
    // [ linear, non-Linear, color ]
    ['None', 'None', '#8dd3c7'],
    ['LN: LNBJ', 'NL: NLBJ', '#ffffb3'],
    ['LN: SCIPY', null, '#bebada'],
    ['LN: RUNONCE', 'NL: RUNONCE', '#fb8072'],
    ['LN: Direct', null, '#80b1d3'],
    ['LN: PETScKrylov', null, '#fdb462'],
    ['LN: LNBGS', 'NL: NLBGS', '#b3de69'],
    ['LN: USER', null, '#fccde5'],
    [null, 'NL: Newton', '#d9d9d9'],
    [null, 'BROYDEN', '#bc80bd'],
    ['solve_linear', 'solve_nonlinear', '#ccebc5'],
    ['other', 'other', '#ffed6f'],
];

N2Style.solverStyleObject = [
    {
        'ln': 'None',
        'nl': 'None',
        'color': '#8dd3c7',
    },
    {
        'ln': 'LN: LNBJ',
        'nl': 'NL: NLBJ',
        'color': '#ffffb3',
    },
    {
        'ln': 'LN: SCIPY',
        'nl': null,
        'color': '#bebada',
    },
    {
        'ln': 'LN: RUNONCE',
        'nl': 'NL: RUNONCE',
        'color': '#fb8072',
    },
    {
        'ln': 'LN: Direct',
        'nl': null,
        'color': '#80b1d3',
    },
    {
        'ln': 'LN: PETScKrylov',
        'nl': null,
        'color': '#fdb462',
    },
    {
        'ln': 'LN: LNBGS',
        'nl': 'NL: NLBGS',
        'color': '#b3de69',
    },
    {
        'ln': 'LN: USER',
        'nl': null,
        'color': '#fccde5',
    },
    {
        'ln': null,
        'nl': 'NL: Newton',
        'color': '#d9d9d9',
    },
    {
        'ln': null,
        'nl': 'BROYDEN',
        'color': '#bc80bd',
    },
    {
        'ln': 'solve_linear',
        'nl': 'solve_nonlinear',
        'color': '#ccebc5',
    },
    {
        'ln': 'other',
        'nl': 'other',
        'color': '#ffed6f',
    },
];

Object.freeze(N2Style.solverStyleData); // Make it the equivalent of a constant

</script>

    <script type="text/javascript">
/**
 * Calculates and stores the size and positions of visible elements.
 * @typedef N2Layout
 * @property {ModelData} model Reference to the preprocessed model.
 * @property {N2TreeNode} zoomedElement Reference to zoomedElement managed by N2Diagram.
 * @property {N2TreeNode[]} zoomedNodes  Child workNodes of the current zoomed element.
 * @property {N2TreeNode[]} visibleNodes Zoomed workNodes that are actually drawn.
 * @property {N2TreeNode[]} zoomedSolverNodes Child solver workNodes of the current zoomed element.
 * @property {Object} svg Reference to the top-level SVG element in the document.
 * @property {Object} size The dimensions of the model and solver trees.
 */
class N2Layout {

    /**
     * Compute the new layout based on the model data and the zoomed element.
     * @param {ModelData} model The pre-processed model object.
     * @param {Object} newZoomedElement The element the new layout is based around.
     * @param {boolean} showLinearSolverNames Whether to show linear or non-linear solver names.
     * @param {Object} dims The initial sizes for multiple tree elements.
     */
    constructor(model, newZoomedElement, showLinearSolverNames, dims) {
        this.model = model;

        this.zoomedElement = newZoomedElement;
        this.showLinearSolverNames = showLinearSolverNames;

        this.outputNamingType = "Absolute";
        this.zoomedNodes = [];
        this.visibleNodes = [];

        this.zoomedSolverNodes = [];
        this.visibleSolverNodes = [];
        this.curVisibleNodeCount = 0;
        this.prevVisibleNodeCount = 0;

        // Initial size values derived from read-only defaults
        this.size = dims.size;
        this.svg = d3.select("#svgId");

        startTimer('N2Layout._computeLeaves');
        this._computeLeaves();
        stopTimer('N2Layout._computeLeaves');

        this._setupTextRenderer();
        startTimer('N2Layout._updateTextWidths');
        this._updateTextWidths();
        stopTimer('N2Layout._updateTextWidths');

        startTimer('N2Layout._updateSolverTextWidths');
        this._updateSolverTextWidths();
        stopTimer('N2Layout._updateSolverTextWidths');
        delete (this.textRenderer);

        startTimer('N2Layout._computeColumnWidths');
        this._computeColumnWidths();
        stopTimer('N2Layout._computeColumnWidths');

        startTimer('N2Layout._computeSolverColumnWidths');
        this._computeSolverColumnWidths();
        stopTimer('N2Layout._computeSolverColumnWidths');

        startTimer('N2Layout._setColumnLocations');
        this._setColumnLocations();
        stopTimer('N2Layout._setColumnLocations');

        startTimer('N2Layout._computeNormalizedPositions');
        this._computeNormalizedPositions(this.model.root, 0, false, null);
        stopTimer('N2Layout._computeNormalizedPositions');
        if (this.zoomedElement.parent)
            this.zoomedNodes.push(this.zoomedElement.parent);

        startTimer('N2Layout._computeSolverNormalizedPositions');
        this._computeSolverNormalizedPositions(this.model.root, 0, false, null);
        stopTimer('N2Layout._computeSolverNormalizedPositions');
        if (this.zoomedElement.parent)
            this.zoomedSolverNodes.push(this.zoomedElement.parent);

        this.setTransitionPermission();

    }

    /**
     * If there are too many nodes, don't bother with transition animations
     * because it will cause lag and may timeout anyway. This is accomplished
     * by redefining a few D3 methods to return the same selection instead
     * of a transition object. When the number of nodes is low enough,
     * the original transition methods are restored.
     */
    setTransitionPermission() {
        this.prevVisibleNodeCount = this.visibleNodeCount;
        this.visibleNodeCount = this.visibleNodes.length;
        const highWaterMark = Math.max(this.prevVisibleNodeCount, this.visibleNodeCount);

        // Too many nodes, disable transitions.
        if (highWaterMark >= N2TransitionDefaults.maxNodes) {
            debugInfo("Denying transitions: ", this.visibleNodes.length,
                " visible nodes, max allowed: ", N2TransitionDefaults.maxNodes)

            // Return if already denied
            if (!d3.selection.prototype.transitionAllowed) return;
            d3.selection.prototype.transitionAllowed = false;

            d3.selection.prototype.transition = returnThis;
            d3.selection.prototype.duration = returnThis;
            d3.selection.prototype.delay = returnThis;
        }
        else { // OK, enable transitions.
            debugInfo("Allowing transitions: ", this.visibleNodes.length,
                " visible nodes, max allowed: ", N2TransitionDefaults.maxNodes)

            // Return if already allowed
            if (d3.selection.prototype.transitionAllowed) return;
            d3.selection.prototype.transitionAllowed = true;

            for (const func in d3.selection.prototype.originalFuncs) {
                d3.selection.prototype[func] =
                    d3.selection.prototype.originalFuncs[func];
            }
        }
    }

    /** Create an off-screen area to render text for _getTextWidth() */
    _setupTextRenderer() {
        const textGroup = this.svg.select('#text-width-renderer');
        const textSVG = textGroup.select('text');

        this.textRenderer = {
            'group': textGroup,
            'textSvg': textSVG,
            'workNode': textSVG.node(),
            'widthCache': {}
        };
    }

    /** Insert text into an off-screen SVG text object to determine the width.
     * Cache the result so repeat calls with the same text can just do a lookup.
     * @param {string} text Text to render or find in cache.
     * @return {number} The SVG-computed width of the rendered string.
     */
    _getTextWidth(text) {
        let width = 0.0;

        // Check cache first
        if (this.textRenderer.widthCache.propExists(text)) {
            width = this.textRenderer.widthCache[text];
        }
        else {
            // Not found, render and return new width.
            this.textRenderer.textSvg.text(text);
            width = this.textRenderer.workNode.getBoundingClientRect().width;

            this.textRenderer.widthCache[text] = width;
        }

        return width;
    }

    /** Determine the text associated with the node. Normally its name,
     * but can be changed if promoted.
     * @param {N2TreeNode} node The item to operate on.
     * @return {string} The selected text.
     */
    getText(node) {
        testThis(this, 'N2Layout', 'getText');

        let retVal = node.name;

        if (this.outputNamingType == "Promoted" &&
            node.isInputOrOutput() &&
            this.zoomedElement.propExists('promotions') &&
            this.zoomedElement.promotions.propExists(node.absPathName)) {
            retVal = this.zoomedElement.promotions[node.absPathName];
        }

        return retVal;
    }

    /**
     * Return the name of the linear or non-linear solver depending
     * on the current setting.
     * @param {N2TreeNode} node The item to get the solver text from.
     */
    getSolverText(node) {
        testThis(this, 'N2Layout', 'getSolverText');

        let solver_name = this.showLinearSolverNames ? node.linear_solver : node.nonlinear_solver;

        if (!this.showLinearSolverNames && node.hasOwnProperty("solve_subsystems") && node.solve_subsystems) {
            return solver_name + " (sub_solve)";
        }
        else {
            return solver_name;
        }
    }

    /**
     * Determine text widths for all descendents of the specified node.
     * @param {N2TreeNode} [node = this.zoomedElement] Item to begin looking from.
     */
    _updateTextWidths(node = this.zoomedElement) {
        if (node.varIsHidden) return;

        node.nameWidthPx = this._getTextWidth(this.getText(node)) + 2 *
            this.size.rightTextMargin;

        if (node.hasChildren() && !node.isMinimized) {
            for (let child of node.children) {
                this._updateTextWidths(child);
            }
        }
    }

    /**
     * Determine text width for this and all decendents if node is a solver.
     * @param {N2TreeNode} [node = this.zoomedElement] Item to begin looking from.
     */
    _updateSolverTextWidths(node = this.zoomedElement) {
        if (node.isInput() || node.varIsHidden) {
            return;
        }

        node.nameSolverWidthPx = this._getTextWidth(this.getSolverText(node)) + 2 *
            this.size.rightTextMargin;

        if (node.hasChildren() && !node.isMinimized) {
            for (let child of node.children) {
                this._updateSolverTextWidths(child);
            }
        }
    }

    /** Recurse through the tree and add up the number of leaves that each
     * node has, based on their array of visible children.
     * @param {N2TreeNode} [node = this.model.root] The starting node.
     */
    _computeLeaves(node = this.model.root) {
        node.numLeaves = 0;

        if (! node.varIsHidden) {
            if (this.model.nodeIds.length > ALLOW_PRECOLLAPSE_COUNT) {
                node.minimizeIfLarge();
            }

            if (node.hasChildren() && !node.isMinimized) {
                for (let child of node.children) {
                    this._computeLeaves(child);
                    node.numLeaves += child.numLeaves;
                }
            }
            else {
                node.numLeaves = 1;
            }
        }
    }

    /** For visible nodes with children, choose a column width
     * large enough to accomodate the widest label in their column.
     * @param {N2TreeNode} node The item to operate on.
     * @param {string} childrenProp Either 'children' or 'subsystem_children'.
     * @param {Object[]} colArr The array of column info.
     * @param {number[]} leafArr The array of leaf width info.
     * @param {string} widthProp Either 'nameWidthPx' or 'nameSolverWidthPx'.
     */
    _setColumnWidthsFromWidestText(node, childrenProp, colArr, leafArr, widthProp) {
        if (node.varIsHidden) return;

        let height = this.size.n2matrix.height * node.numLeaves / this.zoomedElement.numLeaves;
        node.prevTextOpacity = node.propExists('textOpacity') ? node.textOpacity : 0;
        node.textOpacity = (height > this.size.font) ? 1 : 0;
        let hasVisibleDetail = (height >= 2.0);
        let width = (hasVisibleDetail) ? this.size.minColumnWidth : 1e-3;
        if (node.textOpacity > 0.5) width = node[widthProp];

        this.greatestDepth = Math.max(this.greatestDepth, node.depth);

        if (node.hasChildren(childrenProp) && !node.isMinimized) { //not leaf
            colArr[node.depth].width = Math.max(colArr[node.depth].width, width)
            for (let child of node[childrenProp]) {
                this._setColumnWidthsFromWidestText(child, childrenProp, colArr, leafArr, widthProp);
            }
        }
        else { //leaf
            leafArr[node.depth] = Math.max(leafArr[node.depth], width);
        }
    }

    /** Compute column widths across the model, then adjust ends as needed.
     * @param {N2TreeNode} [node = this.zoomedElement] Item to operate on.
     */
    _computeColumnWidths(node = this.zoomedElement) {
        this.greatestDepth = 0;
        this.leafWidthsPx = new Array(this.model.maxDepth + 1).fill(0.0);
        this.cols = Array.from({
            length: this.model.maxDepth + 1
        }, () =>
            ({
                'width': 0.0,
                'location': 0.0
            }));

        this._setColumnWidthsFromWidestText(node, 'children', this.cols,
            this.leafWidthsPx, 'nameWidthPx');

        let sum = 0;
        let lastColumnWidth = 0;
        for (let i = this.leafWidthsPx.length - 1; i >= this.zoomedElement.depth; --i) {
            sum += this.cols[i].width;
            let lastWidthNeeded = this.leafWidthsPx[i] - sum;
            lastColumnWidth = Math.max(lastWidthNeeded, lastColumnWidth);
        }

        this.cols[this.zoomedElement.depth - 1].width = this.size.parentNodeWidth;
        this.cols[this.greatestDepth].width = lastColumnWidth;
    }

    /** Compute solver column widths across the model, then adjust ends as needed.
     * @param {N2TreeNode} [node = this.zoomedElement] Item to operate on.
     */
    _computeSolverColumnWidths(node = this.zoomedElement) {
        this.greatestDepth = 0;
        this.leafSolverWidthsPx = new Array(this.model.maxDepth + 1).fill(0.0);
        this.solverCols = Array.from({
            length: this.model.maxDepth + 1
        }, () =>
            ({
                'width': 0.0,
                'location': 0.0
            }));

        this._setColumnWidthsFromWidestText(node, 'subsystem_children', this.solverCols,
            this.leafSolverWidthsPx, 'nameSolverWidthPx');

        let sum = 0;
        let lastColumnWidth = 0;
        for (let i = this.leafSolverWidthsPx.length - 1; i >= this.zoomedElement.depth; --i) {
            sum += this.solverCols[i].width;
            let lastWidthNeeded = this.leafSolverWidthsPx[i] - sum;
            lastColumnWidth = Math.max(lastWidthNeeded, lastColumnWidth);
        }

        this.solverCols[this.zoomedElement.depth - 1].width = this.size.parentNodeWidth;
        this.solverCols[this.greatestDepth].width = lastColumnWidth;
    }

    /** Set the location of the columns based on the width of the columns
     * to the left.
     */
    _setColumnLocations() {
        this.size.partitionTree.width = 0;
        this.size.solverTree.width = 0;

        for (let depth = 1; depth <= this.model.maxDepth; ++depth) {
            this.cols[depth].location = this.size.partitionTree.width;
            this.size.partitionTree.width += this.cols[depth].width;

            this.solverCols[depth].location = this.size.solverTree.width;
            this.size.solverTree.width += this.solverCols[depth].width;
        }

    }

    /**TODO: _computeNormalizedPositions and _computeSolverNormalizedPositions do almost
     * identical things, just storing info in different variables, so they should be
     * merged as much as possible.
     */

    /**
     * Recurse over the model tree and determine the coordinates and
     * size of visible nodes. If a parent is minimized, operations are
     * performed on it instead.
     * @param {N2TreeNode} node The node to operate on.
     * @param {number} leafCounter Tally of leaves encountered so far.
     * @param {Boolean} isChildOfZoomed Whether node is a descendant of this.zoomedElement.
     * @param {Object} earliestMinimizedParent The minimized parent, if any, appearing
     *   highest in the tree hierarchy. Null if none exist.
     */
    _computeNormalizedPositions(node, leafCounter,
        isChildOfZoomed, earliestMinimizedParent) {
        if (!isChildOfZoomed) {
            isChildOfZoomed = (node === this.zoomedElement);
        }

        if (earliestMinimizedParent == null && isChildOfZoomed) {
            if (!node.varIsHidden) this.zoomedNodes.push(node);
            if (!node.hasChildren() || node.isMinimized) { // at a "leaf" node
                if (!node.varIsHidden) this.visibleNodes.push(node);
                earliestMinimizedParent = node;
            }
        }

        let workNode = (earliestMinimizedParent) ? earliestMinimizedParent : node;
        node.preserveDims(false, leafCounter);

        node.dims.x = this.cols[workNode.depth].location / this.size.partitionTree.width;
        node.dims.y = leafCounter / this.model.root.numLeaves;
        node.dims.width = (node.hasChildren() && !node.isMinimized) ?
            (this.cols[workNode.depth].width / this.size.partitionTree.width) : 1 - workNode.dims.x;
        node.dims.height = workNode.numLeaves / this.model.root.numLeaves;

        if (node.varIsHidden) { // input or hidden leaf leaving
            node.dims.x = this.cols[node.parentComponent.depth + 1].location / this.size.partitionTree.width;
            node.dims.y = node.parentComponent.dims.y;
            node.dims.width = node.dims.height = 1e-6;
        }

        if (node.hasChildren()) {
            for (let child of node.children) {
                this._computeNormalizedPositions(child, leafCounter,
                    isChildOfZoomed, earliestMinimizedParent);
                if (earliestMinimizedParent == null) { //numleaves is only valid passed nonminimized nodes
                    leafCounter += child.numLeaves;
                }
            }
        }
    }

    /**
     * Recurse over the model tree and determine the coordinates and size of visible
     * solver nodes. If a parent is minimized, operations are performed on it instead.
     * @param {N2TreeNode} node The node to operate on.
     * @param {number} leafCounter Tally of leaves encountered so far.
     * @param {Boolean} isChildOfZoomed Whether node is a descendant of this.zoomedElement.
     * @param {Object} earliestMinimizedParent The minimized parent, if any, appearing
     *   highest in the tree hierarchy. Null if none exist.
     */
    _computeSolverNormalizedPositions(node, leafCounter,
        isChildOfZoomed, earliestMinimizedParent) {
        if (!isChildOfZoomed) {
            isChildOfZoomed = (node === this.zoomedElement);
        }

        if (earliestMinimizedParent == null && isChildOfZoomed) {
            if (node.type.match(/^(subsystem|root)$/)) {
                this.zoomedSolverNodes.push(node);
            }
            if (!node.hasChildren() || node.isMinimized) { //at a "leaf" workNode
                if (!node.isInput() && !node.varIsHidden) {
                    this.visibleSolverNodes.push(node);
                }
                earliestMinimizedParent = node;
            }
        }

        let workNode = (earliestMinimizedParent) ? earliestMinimizedParent : node;
        node.preserveDims(true, leafCounter);

        node.solverDims.x = this.solverCols[workNode.depth].location / this.size.solverTree.width;
        node.solverDims.y = leafCounter / this.model.root.numLeaves;
        node.solverDims.width = (node.subsystem_children && !node.isMinimized) ?
            (this.solverCols[workNode.depth].width / this.size.solverTree.width) :
            1 - workNode.solverDims.x;

        node.solverDims.height = workNode.numLeaves / this.model.root.numLeaves;

        if (node.varIsHidden) { //input or hidden leaf leaving
            node.solverDims.x = this.cols[node.parentComponent.depth + 1].location /
                this.size.partitionTree.width;
            node.solverDims.y = node.parentComponent.dims.y;
            node.solverDims.width = node.solverDims.height = 1e-6;
        }

        if (node.hasChildren()) {
            for (let child of node.children) {
                this._computeSolverNormalizedPositions(child,
                    leafCounter, isChildOfZoomed, earliestMinimizedParent);
                if (earliestMinimizedParent == null) { //numleaves is only valid passed nonminimized nodes
                    leafCounter += child.numLeaves;
                }
            }
        }
    }

    /**
     * Calculate new dimensions for the div element enclosing the main SVG element.
     * @returns {Object} Members width and height as strings with the unit appended.
     */
    newOuterDims() {
        let width = (this.size.partitionTree.width +
            this.size.n2matrix.margin +
            this.size.n2matrix.width +
            this.size.solverTree.width +
            this.size.n2matrix.margin);

        let height = (this.size.n2matrix.height +
            this.size.n2matrix.margin * 2);

        return ({
            'width': width,
            'height': height
        });
    }

    /**
     * Calculate new dimensions for the main SVG element.
     * @returns {Object} Members width and height as numbers.
     */
    newInnerDims() {
        let width = this.size.partitionTree.width +
            this.size.n2matrix.margin +
            this.size.n2matrix.width +
            this.size.solverTree.width +
            this.size.n2matrix.margin;

        let height = this.size.partitionTree.height;
        let margin = this.size.n2matrix.margin;

        return ({
            'width': width,
            'height': height,
            'margin': margin
        });
    }

    /**
     * Update container element dimensions when a new layout is calculated,
     * and set up transitions.
     * @param {Object} dom References to HTML elements.
     * @param {number} transitionStartDelay ms to wait before performing transition
     */
    updateTransitionInfo(dom, transitionStartDelay, manuallyResized) {

        sharedTransition = d3.transition()
            .duration(N2TransitionDefaults.duration)
            .delay(transitionStartDelay)
            // Hide the transition waiting animation when it ends:
            .on('end', function() { dom.waiter.attr('class', 'no-show'); });

        this.transitionStartDelay = N2TransitionDefaults.startDelay;

        let outerDims = this.newOuterDims();
        let innerDims = this.newInnerDims();

        this.ratio = (window.innerWidth - 200) / outerDims.width;
        if (this.ratio > 1 || manuallyResized) this.ratio = 1;
        else if (this.ratio < 1)
            debugInfo("Scaling diagram to " + Math.round(this.ratio * 100) + "%");

        dom.svgDiv
            .style("width", (outerDims.width * this.ratio) + this.size.unit)
            .style("height", (outerDims.height * this.ratio) + this.size.unit)

        dom.svg
            .transition(sharedTransition)
            .style("transform", "scale(" + this.ratio + ")")
            .attr("width", outerDims.width + this.size.unit)
            .attr("height", outerDims.height + this.size.unit);

        this.gapDist = (this.size.partitionTreeGap * this.ratio) - 3;
        this.gapSpace = this.gapDist + this.size.unit
        d3.select('#n2-resizer-box')
            .transition(sharedTransition)
            .style('bottom', this.gapSpace);

        dom.pTreeGroup
            .transition(sharedTransition)
            .attr("height", innerDims.height)
            .attr("width", this.size.partitionTree.width)
            .attr("transform", "translate(0 " + innerDims.margin + ")");

        dom.highlightBar
            .transition(sharedTransition)
            .attr("height", innerDims.height)
            .attr("width", "8")
            .attr("transform", "translate(" + this.size.partitionTree.width + 1 + " " + innerDims.margin + ")");

        // Move n2 outer group to right of partition tree, spaced by the margin.
        dom.n2OuterGroup
            .transition(sharedTransition)
            .attr("height", outerDims.height)
            .attr("width", outerDims.height)
            .attr("transform", "translate(" +
                (this.size.partitionTree.width) + " 0)");

        dom.n2InnerGroup.transition(sharedTransition)
            .attr("height", innerDims.height)
            .attr("width", innerDims.height)
            .attr("transform", "translate(" + innerDims.margin + " " + innerDims.margin + ")");

        dom.n2BackgroundRect.transition(sharedTransition)
            .attr("width", innerDims.height)
            .attr("height", innerDims.height)
            .attr("transform", "translate(0 0)");

        dom.pSolverTreeGroup.transition(sharedTransition)
            .attr("height", innerDims.height)
            .attr("transform", "translate(" + (this.size.partitionTree.width +
                innerDims.margin +
                innerDims.height +
                innerDims.margin) + " " +
                innerDims.margin + ")");
    }

    calcWidthBasedOnNewHeight(height) {
        return this.size.partitionTree.width + height + this.size.solverTree.width +
            this.size.n2matrix.margin * 2;
    }

    calcHeightBasedOnNewWidth(width) {
        return width - this.size.partitionTree.width - this.size.solverTree.width -
            this.size.n2matrix.margin * 2;
    }

    calcFitDims() {
        let height = window.innerHeight * 0.95;
        let width = this.calcWidthBasedOnNewHeight(height);

        if (width > window.innerWidth - 200) {
            width = window.innerWidth - 200;
            height = this.calcHeightBasedOnNewWidth(width);
        }

        return { 'width': width, 'height': height };
    }
}

</script>
     <script type="text/javascript">
/** Base class for all cell renderers */
class N2CellRenderer {
    /**
     * Set values shared by objects of all derived class types.
     * @param {string} color The color to render all shapes in.
     * @param {string} className The CSS class to tag primary shapes with, used for selecting.
     */
    constructor(color, className, id) {
        this.color = color;
        this.className = className;
        this.id = 'cellShape_' + id; // To ensure it doesn't start with a number
    }

    static updateDims(baseWidth, baseHeight) {
        if (!N2CellRenderer.dims) {
            N2CellRenderer.prevDims = {
                "size": {
                    "width": 0,
                    "height": 0
                },
                "bottomRight": {
                    "x": 0,
                    "y": 0
                },
                "topLeft": {
                    "x": 0,
                    "y": 0
                }
            }
        }
        else {
            for (let prop of ["size", "bottomRight", "topLeft"]) {
                Object.assign(N2CellRenderer.prevDims[prop],
                    N2CellRenderer.dims[prop]);
            }
        }

        N2CellRenderer.dims = {
            "size": {
                "width": baseWidth,
                "height": baseHeight
            },
            "bottomRight": {
                "x": baseWidth * .5,
                "y": baseHeight * .5
            },
            "topLeft": {
                "x": baseWidth * -.5,
                "y": baseHeight * -.5
            }
        }
    }

    /** Enable access to the static dims variable through "this". */
    get dims() {
        return N2CellRenderer.dims;
    }

    /** Enable access to the static prevDims variable through "this". */
    get prevDims() {
        return N2CellRenderer.prevDims;
    }

    /** Act like an abstract base class force derived classes to define. */
    update() {
        throw ("ERROR: N2CellRenderer.update() called.")
    }

    /** Act like an abstract base class force derived classes to define. */
    render() {
        throw ("ERROR: N2CellRenderer.render() called.")
    }

    /** Reposition an SVG element based on dimensions of the current cell size. */
    updateCurrent(svgGroup) {
        return this.update(svgGroup, this.dims);
    }

    /** Reposition an SVG element based on dimensions of the previous cell size. */
    updatePrevious(svgGroup) {
        return this.update(svgGroup, this.prevDims);
    }

    /** Add an SVG element based on dimensions of the current cell size. */
    renderCurrent(svgGroup) {
        return this.render(svgGroup, this.dims);
    }

    /** Add an SVG element based on dimensions of the previous cell size. */
    renderPrevious(svgGroup) {
        return this.render(svgGroup, this.prevDims);
    }
}

/** Draws/updates an SVG circle for scalar types, with a transition animation. */
class N2ScalarBase extends N2CellRenderer {

    /**
     * Invoke the superclass constructor with these values and "sMid" as a CSS class.
     * @param {Object} dims Layout and dimensions for the current cell spec.
     * @param {Object} prevDims Layout and dimensions for the previous cell spec.
     * @param {string} color The color to render all shapes in.
     */
    constructor(color, id) {
        super(color, "sMid", id);
    }

    /**
     * Select the element with D3 if not already done, attach a transition
     * and resize the shape.
     * @param svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while resizing/repositioning.
     * @param {selection} [d3Elem = null ] The selection created in render().
     */
    update(svgGroup, dims, d3Elem = null) {
        if (!d3Elem) d3Elem = d3.select(svgGroup).select("." + this.className)
            .transition(sharedTransition);
        return d3Elem
            .attr("rx", dims.bottomRight.x * .6)
            .attr("ry", dims.bottomRight.y * .6);
    }

    /** 
     * Get the D3 selection for the appropriate group and append a filled ellipse.
     * @param {Object} svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while rendering.
     */
    render(svgGroup, dims) {
        let d3Elem = d3.select(svgGroup)
            .append("ellipse")
            .attr("class", this.className)
            .attr("id", this.id)
            .style("fill", this.color);

        return this.update(svgGroup, dims, d3Elem)
    }
}

/** Draws/updates an SVG rect for vector types, with a transition animation. */
class N2VectorBase extends N2CellRenderer {

    /**
     * Invoke the superclass constructor with these values and "vMid" as a CSS class.
     * @param {Object} dims Layout and dimensions for the current cell spec.
     * @param {Object} prevDims Layout and dimensions for the previous cell spec.
     * @param {string} color The color to render all shapes in.
     */
    constructor(color, id) {
        super(color, "vMid", id);
    }

    /**
     * Select the element with D3 if not already done, attach a transition
     * and resize the shape.
     * @param svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while resizing/repositioning.
     * @param {selection} [d3Elem = null ] The selection created in render().
     */
    update(svgGroup, dims, d3Elem = null) {
        if (!d3Elem) d3Elem = d3.select(svgGroup).select("." + this.className)
            .transition(sharedTransition);

        let ret = d3Elem
            .attr("x", dims.topLeft.x * .6)
            .attr("y", dims.topLeft.y * .6)
            .attr("width", dims.bottomRight.x * 1.2)
            .attr("height", dims.bottomRight.y * 1.2);

        return ret;
    }

    /** 
     * Get the D3 selection for the appropriate group and append a filled rectangle.
     * @param {Object} svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while rendering.
     */
    render(svgGroup, dims) {
        let d3Elem = d3.select(svgGroup).append('rect')
            .attr("class", this.className)
            .attr("id", this.id)
            .style("fill", this.color);

        return this.update(svgGroup, dims, d3Elem);
    }
}

class N2Connector extends N2CellRenderer {
    /**
     * Invoke the superclass constructor with these values and "vMid" as a CSS class.
     * @param {Object} dims Layout and dimensions for the current cell spec.
     * @param {Object} prevDims Layout and dimensions for the previous cell spec.
     * @param {string} color The color to render all shapes in.
     */
    constructor(color, id) {
        super(color, "vMid", id);
    }

    _transform(scale) { throw ("ERROR: N2Connector._transform() called.") }

    /**
     * Select the element with D3 if not already done, attach a transition
     * and resize the shape.
     * @param svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while resizing/repositioning.
     * @param {selection} [d3Elem = null ] The selection created in render().
     */
    update(svgGroup, dims, d3Elem = null) {
        if (!d3Elem) d3Elem = d3.select(svgGroup).select("." + this.className)
            .transition(sharedTransition);

        let ret = d3Elem.attr("transform", this._transform(dims.size.width/10.0));

        return ret;
    }

    /** 
     * Get the D3 selection for the appropriate group and append a filled arrow.
     * @param {Object} svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while rendering.
     */
    render(svgGroup, dims) {
        let d3Elem = d3.select(svgGroup).append('use')
            .attr("class", this.className)
            .attr("id", this.id)
            .style("fill", this.color)
            .attr("x", -5)
            .attr("y", -5)
            .attr("xlink:href", "#matrix-connector-square")

        return this.update(svgGroup, dims, d3Elem);
    }
}

/** Draws/updates an SVG rect with a border for group types, with a transition animation. */
class N2GroupBase extends N2CellRenderer {
    /**
     * Invoke the superclass constructor with these values and "gMid" as a CSS class.
     * @param {Object} dims Layout and dimensions for the current cell spec.
     * @param {Object} prevDims Layout and dimensions for the previous cell spec.
     * @param {string} color The color to render all shapes in.
     */
    constructor(color, id) {
        super(color, "gMid", id);
    }

    /**
     * Select the each of the border elements with D3 if not already done,
     * attach a transition and resize each shape individually.
     * @param {Object} dims The cell spec to use while resizing/repositioning.
     * @param {selection} d3Group The pre-selected group to work with.
     * @param {Array} border Border selections created in _renderBorder().
     */
    _updateBorder(dims, d3Group, border) {
        if (!border) {
            // Find the existing border rects if not provided.
            border = [
                d3Group.select(".bordR1").transition(sharedTransition),
                d3Group.select(".bordR2").transition(sharedTransition),
                d3Group.select(".bordR3").transition(sharedTransition),
                d3Group.select(".bordR4").transition(sharedTransition)
            ];
        }

        border[0]
            .attr("x", dims.topLeft.x).attr("y", dims.topLeft.y)
            .attr("width", dims.size.width).attr("height", dims.size.height * .1);

        border[1]
            .attr("x", dims.topLeft.x).attr("y", dims.topLeft.y)
            .attr("width", dims.size.width * .1).attr("height", dims.size.height);

        border[2]
            .attr("x", dims.bottomRight.x * .8).attr("y", dims.topLeft.y)
            .attr("width", dims.size.width * .1).attr("height", dims.size.height);

        border[3]
            .attr("x", dims.topLeft.x).attr("y", dims.bottomRight.y * .8)
            .attr("width", dims.size.width).attr("height", dims.size.height * .1);
    }

    /**
     * Draw four skinny rectangles at the perimeter of the group.
     * @param {Object} d3Group D3 selection for the group that we add to.
     */
    _renderBorder(d3Group) {
        let border = [
            d3Group.append("rect").attr("class", "bordR1").style("fill", this.color),
            d3Group.append("rect").attr("class", "bordR2").style("fill", this.color),
            d3Group.append("rect").attr("class", "bordR3").style("fill", this.color),
            d3Group.append("rect").attr("class", "bordR4").style("fill", this.color)
        ];

        return border;
    }

    /**
     * Select the element with D3 if not already done, attach a transition
     * and resize the shape.
     * @param svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while resizing/repositioning.
     * @param {selection} [d3Elem = null] The selection created in render().
     * @param {Array} [border = null] Border selections created in _renderBorder().
     */
    update(svgGroup, dims, d3Elem = null, border = null) {
        let d3Group = d3.select(svgGroup);
        if (!d3Elem) d3Elem = d3Group.select("." + this.className)
            .transition(sharedTransition);

        this._updateBorder(dims, d3Group, border);

        return d3Elem
            .attr("x", dims.topLeft.x * .6)
            .attr("y", dims.topLeft.y * .6)
            .attr("width", dims.size.width * .6)
            .attr("height", dims.size.height * .6);
    }

    /** 
     * Get the D3 selection for the appropriate group and append a filled rectangle,
     * then call _renderBorder() to put a border around it.
     * @param {Object} svgGroup Reference to SVG <g> element associated with data.
     * @param {Object} dims The cell spec to use while rendering.
     */
    render(svgGroup, dims) {
        let d3Group = d3.select(svgGroup);
        let border = this._renderBorder(d3Group);
        let d3Elem = d3Group
            .append("rect")
            .attr("class", this.className)
            .attr("id", this.id)
            .style("fill", this.color);

        return this.update(svgGroup, dims, d3Elem, border);
    }
}

class N2ScalarCell extends N2ScalarBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2VectorCell extends N2VectorBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2GroupCell extends N2GroupBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2ScalarScalarCell extends N2ScalarBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2ScalarVectorCell extends N2VectorBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2VectorScalarCell extends N2VectorBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2VectorVectorCell extends N2VectorBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2ConnectorUpper extends N2Connector {
    constructor(color, id) {
        super(color, id);
    }

    /** Generate a string to use for the transform attribute */
    _transform(scale) { return('scale(' + scale + ')'); }
}

class N2ConnectorLower extends N2Connector {
    constructor(color, id) {
        super(color, id);
    }

    /** Generate a string to use for the transform attribute */
    _transform(scale) { return('scale(' + scale + ') rotate(180)'); }
}

class N2ScalarGroupCell extends N2GroupBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2GroupScalarCell extends N2GroupBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2VectorGroupCell extends N2GroupBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2GroupVectorCell extends N2GroupBase {
    constructor(color, id) {
        super(color, id);
    }
}

class N2GroupGroupCell extends N2GroupBase {
    constructor(color, id) {
        super(color, id);
    }
}

// TODO: Consider moving color management into CSS styles

/**
 * A visible cell in the N2 matrix.
 * @typedef {Object} N2MatrixCell
 * @property {number} row Vertical coordinate of the cell in the matrix.
 * @property {number} col Horizontal coordinate of the cell in the matrix.
 * @property {N2TreeNode} srcObj The node in the model tree this cell is associated with.
 * @property {N2TreeNode} tgtObj The model tree node that this outputs to.
 * @property {string} id The srcObj id appended with the tgtObj id.
 * @property {SymbolType} symbolType Info about the type of symbol represented by the node.
 */
class N2MatrixCell {
    /**
     * Initialize the cell.
     * @param {number} row Vertical coordinate of the cell in the matrix.
     * @param {number} col Horizontal coordinate of the cell in the matrix.
     * @param {N2TreeNode} srcObj The node in the model tree this node is associated with.
     * @param {N2TreeNode} tgtObj The model tree node that this outputs to.
     * @param {ModelData} model Reference to the model to get some info from it.
     * @param {N2CellRenderer} renderer The object that draws the cell.
     */
    constructor(row, col, srcObj, tgtObj, model) {
        this.row = row;
        this.col = col;
        this.srcObj = this.obj = srcObj;
        this.tgtObj = tgtObj;
        this.id = N2MatrixCell.makeId(srcObj.id, tgtObj.id);

        this.symbolType = new SymbolType(this, model);
        this.renderer = this._newRenderer();

        this.offScreen = {
            "top": {
                "incoming": new Set(),
                "outgoing": new Set()
            },
            "bottom": {
                "incoming": new Set(),
                "outgoing": new Set()
            },
            "total": 0
        }
    }

    static makeId(srcId, tgtId = null) {
        if (! tgtId || srcId == tgtId) return "node_" + srcId;
        
        return "conn_" + srcId + "_to_" + tgtId;
    }

    /**
     * Determine if this node is on the main diagonal of the matrix.
     * @return {Boolean} True if row equals column.
     */
    onDiagonal() {
        return (this.row == this.col);
    }

    /**
     * Determine if this node is in the upper-right triangle of the matrix.
     * @return {Boolean} True if column is greater than row.
     */
    inUpperTriangle() {
        return (this.col > this.row);
    }

    /**
     * Determine if this node is in the lower-left triangle of the matrix.
     * @return {Boolean} True if row is greater than column.
     */
    inLowerTriangle() {
        return (this.row > this.col);
    }

    /**
     * Select the mouseover callback depending on whether we're on the diagonal.
     * TODO: Remove these globals
     */
    mouseover() {
        return (this.onDiagonal() ? n2MouseFuncs.overOnDiag :
            n2MouseFuncs.overOffDiag);
    }

    /**
    * Select the mousemove callback depending on whether we're on the diagonal.
    * TODO: Remove these globals
    */
    mousemove() {
        return (this.onDiagonal() ? n2MouseFuncs.moveOnDiag : null);
    }

    /**
     * Choose a color based on our location and state of the associated N2TreeNode.
     */
    color() {
        if (this.symbolType.potentialDeclaredPartial &&
            this.symbolType.declaredPartial) return N2Style.color.declaredPartial;

        if (this.onDiagonal()) {
            if (this.obj.isMinimized) return N2Style.color.collapsed;
            if (this.obj.isAutoIvcInput()) return N2Style.color.autoivcInput;
            if (this.obj.isConnectedInput()) return N2Style.color.input;
            if (this.obj.isUnconnectedInput()) return N2Style.color.unconnectedInput;
            return (this.obj.implicit) ?
                N2Style.color.outputImplicit :
                N2Style.color.outputExplicit;
        }

        return N2Style.color.connection;
    }


    /**
     * A connection going "off-screen" was detected between two nodes.
     * Determine whether the arrow should be in the top or bottom section of the
     * matrix based on rootIndex, and add to the appropriate array of
     * tracked offscreen connections.
     * @param {N2TreeNode} srcNode Where the connection starts.
     * @param {N2TreeNode} tgtNode Where the connection ends.
     */
    addOffScreenConn(srcNode, tgtNode) {
        let debugStr = ": " + srcNode.absPathName + " -> " + tgtNode.absPathName;

        if (srcNode === this.tgtObj) {
            // Outgoing
            if (srcNode.rootIndex < tgtNode.rootIndex) {
                // Top
                debugInfo("New offscreen outgoing connection on top" + debugStr);
                this.offScreen.top.outgoing.add(tgtNode);
            }
            else {
                // Bottom
                debugInfo("New offscreen outgoing connection on bottom" + debugStr);
                this.offScreen.bottom.outgoing.add(tgtNode);
            }
        }
        else {
            // Incoming
            if (srcNode.rootIndex < tgtNode.rootIndex) {
                // Top
                debugInfo("New offscreen incoming connection on top" + debugStr);
                this.offScreen.top.incoming.add(srcNode);
            }
            else {
                // Bottom
                debugInfo("New offscreen incoming connection on bottom" + debugStr);
                this.offScreen.bottom.incoming.add(srcNode);
            }
        }

        this.offScreen.total++;
        // debugInfo("Total offscreen connections found: " + this.offScreen.total);
    }

    /** Choose a renderer based on our SymbolType. */
    _newRenderer() {
        if (this.color() == N2Style.color.connection) {
            if (this.inUpperTriangle()) return new N2ConnectorUpper(this.color(), this.id);

            return new N2ConnectorLower(this.color(), this.id)
        }

        const color = this.color();

        switch (this.symbolType.name) {
            case "scalar":
                return new N2ScalarCell(color, this.id);
            case "vector":
                return new N2VectorCell(color, this.id);
            case "group":
                return new N2GroupCell(color, this.id);
            case "scalarScalar":
                return new N2ScalarScalarCell(color, this.id);
            case "scalarVector":
                return new N2ScalarVectorCell(color, this.id);
            case "vectorScalar":
                return new N2VectorScalarCell(color, this.id);
            case "vectorVector":
                return new N2VectorVectorCell(color, this.id);
            case "scalarGroup":
                return new N2ScalarGroupCell(color, this.id);
            case "groupScalar":
                return new N2GroupScalarCell(color, this.id);
            case "vectorGroup":
                return new N2VectorGroupCell(color, this.id);
            case "groupVector":
                return new N2GroupVectorCell(color, this.id);
            case "groupGroup":
                return new N2GroupGroupCell(color, this.id);
        }
    }

    /**
     * Highlight the variable nodes *associated* with the cell, not the cell
     * itself. The default is for cells on the diagonal to highlight the
     * variable directly across from them.
     * @param {String} [varType = 'self'] Either 'self', 'source', or 'target'
     *   to indicate the variable name to highlight.
     * @param {String} [direction = 'self'] Either 'self', 'input', or 'output'
     *   to indicate the style of the highlighting.
     */
    highlight(varType = 'self', direction = 'self') {

        const obj = (varType == 'target') ? this.tgtObj : this.srcObj;
        const treeId = obj.absPathName.replace(/[\.:]/g, '_');
        const treeNode = d3.select('rect#' + treeId);

        let fill = treeNode.style('fill');
        if (direction == 'input') fill = N2Style.color.inputArrow;
        else if (direction == 'output') fill = N2Style.color.outputArrow;

        d3.select('#highlight-bar').append('rect')
            .attr('x', 0)
            .attr('y', treeNode.node().parentNode.transform.baseVal[0].matrix.f)
            .attr('rx', 4)
            .attr('ry', 4)
            .attr('width', 8)
            .attr('height', treeNode.attr('height'))
            .attr('stroke', N2Style.color.treeStroke)
            .attr('fill', fill);
    }
}

</script>
     <script type="text/javascript">
/**
 * Draw a symbol describing each of the element types.
 * @typedef N2Legend
 * @property {Boolean} shown Whether the legend is currently drawn or not.
 */
class N2Legend {
    /**
     * Initializes the legend object. 
     * @param {ModelData} modelData Symbols are only displayed if they're in the model
     */
    constructor(modelData) {
        this._div = d3.select("#legend-div");

        // TODO: The legend should't have to search through modelData itself,
        // this info can be collected as modelData is built.
        this.nodes = modelData.tree.children;
        this.showSysVar = {
            'group': false,
            'component': false,
            'input': false,
            'unconnectedInput': false,
            'autoivcInput': false,
            'outputExplicit': false,
            'outputImplicit': false,
            'collapsed': true,
            'connection': true,
            'declaredPartial': true
        };

        this.showN2Symbols = {
            'scalar': false,
            'vector': false,
            'collapsedVariables': false
        };

        this.sysAndVar = [
            { 'name': "Connection", 'color': N2Style.color.connection },
            { 'name': "Collapsed", 'color': N2Style.color.collapsed },
            { 'name': "Declared Partial", 'color': N2Style.color.declaredPartial}
        ];

        this.n2Symbols = [];
        const rootLinearSolver =
            N2Style.solverStyleObject.find(x => x.ln === modelData.tree.linear_solver);
        const rootNonLinearSolver =
            N2Style.solverStyleObject.find(x => x.nl === modelData.tree.nonlinear_solver);
        this.linearSolvers = [
            { 'name': modelData.tree.linear_solver, 'color': rootLinearSolver.color }
        ];

        this.nonLinearSolvers = [
            { 'name': modelData.tree.nonlinear_solver, 'color': rootNonLinearSolver.color }
        ];

        this._setDisplayBooleans(this.nodes);
        this._setupContents();

        // Get the initial setting from the style sheet
        this.hidden = (this._div.style('visibility') == 'hidden');

        this._setupDrag();

        let self = this;
        this.closeDiv = d3.select('#close-legend');
        this.closeButton = this.closeDiv.select('p');

        this.closeDiv
            .on('mouseenter', e => { self.closeButton.style('color', 'red'); })
            .on('mouseout', e => { self.closeButton.style('color', 'black'); })
            .on('click', e => { 
                self.hide(); 
                self.closeButton.style('color', 'black');
                d3.select('#legend-button').attr('class', 'fas icon-key');
            })
    }

    _setDisplayBooleans(nodes) {
        for (let node of nodes) {
            const {
                group,
                component,
                input,
                unconnectedInput,
                outputExplicit,
                outputImplicit,
                collapsed,
                connection,
                declaredPartial
            } = this.showSysVar;

            const linearSolver = node.linear_solver;
            const nonLinearSolver = node.nonlinear_solver;

            const linearSolverIndex =
                this.linearSolvers.indexOf(this.linearSolvers.find(x => x.name === linearSolver))
            const nonLinearSolverIndex =
                this.nonLinearSolvers.indexOf(this.nonLinearSolvers.find(x => x.name === nonLinearSolver));

            if (linearSolverIndex < 0 && linearSolver !== undefined) {
                let solverStyle = N2Style.solverStyleObject.find(x => x.ln === linearSolver);
                this.linearSolvers.push({
                    'name': solverStyle.ln,
                    'color': solverStyle.color
                });
            }

            if (nonLinearSolverIndex < 0 && nonLinearSolver !== undefined) {
                let solverStyle = N2Style.solverStyleObject.find(x => x.nl === nonLinearSolver);
                this.nonLinearSolvers.push({
                    'name': solverStyle.nl,
                    'color': solverStyle.color
                });
            }

            if (node.hasChildren()) {
                if (!this.showSysVar.group && node.isGroup()) {
                    this.showSysVar.group = true;
                    this.sysAndVar.push({
                        'name': 'Group',
                        'color': N2Style.color.group
                    })
                }
                else if (!this.showSysVar.component && node.isComponent()) {
                    this.showSysVar.component = true;
                    this.sysAndVar.push({
                        'name': 'Component',
                        'color': N2Style.color.component
                    })
                }
                this._setDisplayBooleans(node.children);
            }
            else {
                if (!this.showSysVar.input && node.isInput()) {
                    this.showSysVar.input = true;
                    this.sysAndVar.push({
                        'name': 'Input',
                        'color': N2Style.color.input
                    })
                }
                else if (!this.showSysVar.outputExplicit && node.isExplicitOutput()) {
                    this.showSysVar.outputExplicit = true;
                    this.sysAndVar.push({
                        'name': 'Explicit Output',
                        'color': N2Style.color.outputExplicit
                    })
                }
                else if (!this.showSysVar.outputImplicit && node.isImplicitOutput()) {
                    this.showSysVar.outputImplicit = true;
                    this.sysAndVar.push({
                        'name': 'Implicit Output',
                        'color': N2Style.color.outputImplicit
                    })
                }
                else if (!this.showSysVar.autoivcInput && node.isAutoIvcInput()) {
                    this.showSysVar.autoivcInput = true;
                    this.sysAndVar.push({
                        'name': 'Auto-IVC Input',
                        'color': N2Style.color.autoivcInput
                    })
                }
                else if (!this.showSysVar.unconnectedInput && node.isUnconnectedInput()) {
                    this.showSysVar.unconnectedInput = true;
                    this.sysAndVar.push({
                        'name': 'Unconnected Input',
                        'color': N2Style.color.unconnectedInput
                    })
                }
            }
        }
    }

    /**
     * Create elements in the legend divs for the supplied item
     * @param {Object} item Contains the name and color of the item
     * @param {Object} container The div to append into
     */
    _addItem(item, container) {
        const newDiv = container
            .append('div')
            .attr('class', 'legend-box-container');

        newDiv.append('div')
            .attr('class', 'legend-box')
            .style('background-color', item.color);

        newDiv.append('p')
            .html(item.name);
    }

    /** Add symbols for all of the items that were discovered */
    _setupContents() {
        const sysVarContainer = d3.select('#sys-var-legend');
        for (let item of this.sysAndVar) this._addItem(item, sysVarContainer);

        sysVarContainer.style('width', sysVarContainer.node().scrollWidth + 'px')

        const solversLegend = d3.select('#solvers-legend')
        for (let item of this.linearSolvers) this._addItem(item, solversLegend);

        solversLegend.style('width', solversLegend.node().scrollWidth + 'px');

    }

    /** Listen for the event to begin dragging the legend */
    _setupDrag() {
        const self = this;

        this._div.on('mousedown', function() {
            let dragDiv = d3.select(this);
            dragDiv.style('cursor', 'grabbing')
                // top style needs to be set explicitly before releasing bottom:
                .style('top', dragDiv.style('top'))   
                .style('bottom', 'initial');

            self._startPos = [d3.event.clientX, d3.event.clientY]
            self._offset = [d3.event.clientX - parseInt(dragDiv.style('left')), 
                d3.event.clientY - parseInt(dragDiv.style('top'))];

            let w = d3.select(window)
                .on("mousemove", e => {
                    dragDiv
                        .style('top', (d3.event.clientY - self._offset[1]) + 'px')
                        .style('left', (d3.event.clientX - self._offset[0]) + 'px');
                })
                .on("mouseup", e => {
                    dragDiv.style('cursor', 'grab');
                    w.on("mousemove", null).on("mouseup", null);
                    
                });

            d3.event.preventDefault();
        })
    }

    hide() {
        this._div.style('visibility', 'hidden');
        this.hidden = true;
    }

    show() {
        this._div.style('visibility', 'visible');
        this.hidden = false;
    }

    /**
     * Wipe the current solvers legend area and populate with the other type.
     * @param {Boolean} linear True to use linear solvers, false for non-linear.
     */
    toggleSolvers(linear) {

        const solversLegendTitle = d3.select('#solvers-legend-title');
        solversLegendTitle.text(linear ? "Linear Solvers" : "Non-Linear Solvers");

        const solversLegend = d3.select('#solvers-legend');
        solversLegend.html('');

        const solvers = linear ? this.linearSolvers : this.nonLinearSolvers;
        for (let item of solvers) this._addItem(item, solversLegend);

        solversLegend.style('width', solversLegend.node().scrollWidth + 'px');
    }

    /**
     * If legend is shown, hide it; if it's hidden, show it.
     * @param {Boolean} showLinearSolverNames Determines solver name type displayed.
     * @param {Object} solverStyles Solver names, types, and styles including color.
     */
    toggle(showLinearSolverNames, solverStyles) {
        if (this.hidden) this.show();
        else this.hide();
    }
}

</script>
     <script type="text/javascript">
/**
 * Use the model tree to build the matrix of variables and connections, display, and
 * perform operations with it.
 * @typedef N2Matrix
 * @property {N2TreeNodes[]} nodes Reference to nodes that will be drawn.
 * @property {ModelData} model Reference to the pre-processed model.
 * @property {N2Layout} layout Reference to object managing columns widths and such.
 * @property {Object} n2Groups References to <g> SVG elements created by N2Diagram.
 * @property {number} levelOfDetailThreshold Don't draw elements below this size in pixels.
 * @property {Object} nodeSize Width and height of each node in the matrix.
 * @property {Object} prevNodeSize Width and height of each node in the previous matrix.
 * @property {Object[][]} grid Object keys corresponding to rows and columns.
 * @property {Array} visibleCells One-dimensional array of all cells, for D3 processing.
 * @property {Array} boxInfo Component box dimensions.
 */
class N2Matrix {
    /**
     * Render the matrix of visible elements in the model.
     * @param {ModelData} model The pre-processed model data.
     * @param {N2Layout} layout Pre-computed layout of the diagram.
     * @param {Object} n2Groups References to <g> SVG elements created by N2Diagram.
     * @param {N2ArrowManager} arrowMgr Object to create and manage conn. arrows.
     * @param {Boolean} lastClickWasLeft
     * @param {function} findRootOfChangeFunction
     */
    constructor(model, layout, n2Groups, arrowMgr,
        lastClickWasLeft,
        findRootOfChangeFunction,
        prevNodeSize = {
            'width': 0,
            'height': 0
        }) {

        this.model = model;
        this.layout = layout;
        this.diagNodes = layout.visibleNodes;
        this.n2Groups = n2Groups;
        this.arrowMgr = arrowMgr;
        this.lastClickWasLeft = lastClickWasLeft;
        this.findRootOfChangeFunction = findRootOfChangeFunction;

        this.prevNodeSize = prevNodeSize;
        this.nodeSize = {
            'width': layout.size.n2matrix.width / this.diagNodes.length,
            'height': layout.size.n2matrix.height / this.diagNodes.length,
        }
        this.arrowMgr.setNodeSize(this.nodeSize);

        let markerSize = Math.max(2, this.nodeSize.width * .04, this.nodeSize.height * .04);
        d3.select("#arrow").attr("markerWidth", markerSize).attr("markerHeight", markerSize);
        d3.select("#offgridArrow").attr("markerWidth", markerSize * 2).attr("markerHeight", markerSize);

        N2CellRenderer.updateDims(this.nodeSize.width, this.nodeSize.height);
        this.updateLevelOfDetailThreshold(layout.size.n2matrix.height);

        startTimer('N2Matrix._buildGrid');
        this._buildGrid();
        stopTimer('N2Matrix._buildGrid');

        startTimer('N2Matrix._setupComponentBoxesAndGridLines');
        this._setupComponentBoxesAndGridLines();
        stopTimer('N2Matrix._setupComponentBoxesAndGridLines');
    }

    get cellDims() {
        return N2CellRenderer.dims;
    }

    get prevCellDims() {
        return N2CellRenderer.prevDims;
    }

    /**
     * Determine if a node exists at the specified location.
     * @param {number} row Row number of the node
     * @param {number} col Column number of the node
     * @returns False if the row doesn't exist or a column doesn't exist
     *  in the row; true otherwise.
     */
    exists(row, col) {
        if (this.grid[row] && this.grid[row][col]) return true;
        return false;
    }

    /**
     * Make sure the cell is still part of the matrix and not an old one.
     * @param {N2MatrixCell} cell The cell to test.
     * @returns {Boolean} True if this.diagNodes has an object in the
     *   same row and column, and it matches the provided cell.
     */
    cellExists(cell) {
        return (this.exists(cell.row, cell.col) &&
            this.cell(cell.row, cell.col) === cell);
    }

    /**
     * Safe method to access a node/cell at the specified location.
     * Renamed from node() which is confusing with D3.
     * @param {number} row Row number of the node
     * @param {number} col Column number of the node
     * @param {boolean} doThrow Whether to throw an exception if node undefined.
     * @returns {N2MatrixCell} The node if it exists, undefined otherwise.
     */
    cell(row, col, doThrow = false) {
        if (this.exists(row, col)) {
            return this.grid[row][col];
        }
        else if (doThrow) {
            throw "No node in matrix at (" + row + ", " + col + ").";
        }

        return undefined;
    }

    findCellById(cellId) {
        for (const cell of this.visibleCells) {
            if (cell.id == cellId) return cell;
        }

        return undefined;
    }

    /**
     * Given the node ID, determine if one of the cells in the matrix
     * represents it or contains it.
     * @param {Number} nodeId The id of the N2TreeNode to search for
     * @returns {Object} Contains reference to cell if found, and flags describing it.
     */
    findCellByNodeId(nodeId) {
        const node = this.model.nodeIds[nodeId];
        let ret = { 
            'cell': undefined,    // Changed to refer to a related cell if found
            'exactMatch': false,  // True if nodeId matches a cell
            'parentMatch': false, // True if nodeId's ancestor is a cell
            'childMatch': false   // True if nodeId's descendant is a cell
        }

        const debugStr = `${node.absPathName}(${nodeId})`

        // Less expensive to check entire matrix for direct matches first
        for (const row in this.grid) { // Check diagonals only
            const cell = this.grid[row][row];

            // Found directly:
            if (cell.id == N2MatrixCell.makeId(nodeId)) {
                debugInfo(`findCellByNodeId: Found ${debugStr} directly in matrix`)
                ret.cell = cell;
                ret.exactMatch = true
                return ret;
            }
        }

        // Only check for relationships if node not directly visible
        for (const row in this.grid) { // Check diagonals only
            const cell = this.grid[row][row];
            if (node.hasNodeInChildren(cell.obj)) {
                debugInfo(`findCellByNodeId: Found descendant of ${debugStr} in matrix`)
                ret.cell = cell;
                ret.childMatch = true
                return ret;
            }

            if (node.hasParent(cell.obj)) {
                debugInfo(`findCellByNodeId: Found ancestor of ${debugStr} in matrix`)
                ret.cell = cell;
                ret.parentMatch = true
                return ret;
            }
        }
    
        // Shouldn't really get here due to zoomedElement check at top
        debugInfo(`findCellByNodeId: ${debugStr} fell through all checks!`)
        return ret;
    }

    /**
     * Compute the new minimum element size when the diagram height changes.
     * @param {number} height In pixels.
     */
    updateLevelOfDetailThreshold(height) {
        this.levelOfDetailThreshold = height / 3;
    }

    /**
     * Compare the number of visible nodes to the amount allowed by
     * the threshold setting.
     */
    tooMuchDetail() {
        let tooMuch = (this.diagNodes.length >= this.levelOfDetailThreshold);

        if (tooMuch) debugInfo("Too much detail.")

        return tooMuch;
    }

    /**
     * Add a cell to the grid Object and visibleCells array, with special
     * handling for declared partials.
     * @param {number} row Index of the row in the grid to place the cell.
     * @param {number} col Index of the column in the grid to place the cell.
     * @param {N2MatrixCell} newCell Cell created in _buildGrid().
     */
    _addCell(row, col, newCell) {
        if (this.model.useDeclarePartialsList &&
            newCell.symbolType.potentialDeclaredPartial &&
            !newCell.symbolType.declaredPartial) {

            return;
        }

        this.grid[row][col] = newCell;
        this.visibleCells.push(newCell);
    }

    /**
     * For cells that are part of cycles, determine if there are parts
     * of the cycle that are offscreen. If so, record them in the cell.
     * @param {N2MatrixCell} cell The cell to check.
     */
    _findUnseenCycleSources(cell) {
        let node = cell.tgtObj;
        let targetsWithCycleArrows = node.getNodesWithCycleArrows();

        for (let twca of targetsWithCycleArrows) {
            for (let ai of twca.cycleArrows) {
                let found = false;

                // Check visible nodes on the diagonal.
                for (let diagNode of this.diagNodes) {
                    let commonParent = diagNode.nearestCommonParent(ai.src);
                    if (diagNode.hasNode(ai.src, commonParent)) {
                        found = true;
                        break;
                    }
                }

                if (!found) {
                    for (let tgt of ai.src.targetParentSet) {
                        if (tgt.absPathName == node.absPathName) {
                            debugInfo("Adding offscreen connection from _findUnseenCycleSources().")
                            cell.addOffScreenConn(ai.src, node)
                        }
                    }
                }
            }
        }
    }

    /**
     * Set up N2MatrixCell arrays resembling a two-dimensional grid as the
     * matrix, but not an actual two dimensional array because most of
     * it would be unused.
     */
    _buildGrid() {
        this.visibleCells = [];
        this.grid = {};

        if (this.tooMuchDetail()) return;

        for (let srcIdx = 0; srcIdx < this.diagNodes.length; ++srcIdx) {
            let diagNode = this.diagNodes[srcIdx];

            // New row
            if (!this.grid.propExists(srcIdx)) this.grid[srcIdx] = {};

            // On the diagonal
            let newDiagCell = new N2MatrixCell(srcIdx, srcIdx, diagNode, diagNode, this.model);
            this._addCell(srcIdx, srcIdx, newDiagCell);
            this._findUnseenCycleSources(newDiagCell);

            for (let tgt of diagNode.targetParentSet) {
                let tgtIdx = indexFor(this.diagNodes, tgt);

                if (tgtIdx != -1) {
                    let newCell = new N2MatrixCell(srcIdx, tgtIdx, diagNode, tgt, this.model);
                    this._addCell(srcIdx, tgtIdx, newCell);
                }
                // Make sure tgt isn't descendant of zoomedElement, otherwise it's
                // visible at least as a collapsed node
                else if (tgt.isConnectable() && !this.layout.zoomedElement.hasNode(tgt)) {
                    newDiagCell.addOffScreenConn(diagNode, tgt);
                }
            }

            // Check for missing source part of connections
            for (let src of diagNode.sourceParentSet) {

                if (indexFor(this.diagNodes, src) == -1) {
                    // Make sure src isn't descendant of zoomedElement, otherwise it's
                    // visiable at least as a collapsed node
                    if (src.isConnectable() && !this.layout.zoomedElement.hasNode(src)) {
                        newDiagCell.addOffScreenConn(src, diagNode);
                    }
                }
            }

            // Solver nodes
            if (diagNode.isInput()) {
                for (let j = srcIdx + 1; j < this.diagNodes.length; ++j) {
                    let tgtObj = this.diagNodes[j];
                    if (diagNode.parentComponent !== tgtObj.parentComponent) break;

                    if (tgtObj.isOutput()) {
                        let tgtIdx = j;
                        let newCell = new N2MatrixCell(srcIdx, tgtIdx, diagNode, tgtObj, this.model);
                        this._addCell(srcIdx, tgtIdx, newCell);
                    }
                }
            }
        }

    }

    /**
     * Determine the size of the boxes that will border the variables of each component.
     */
    _setupComponentBoxesAndGridLines() {
        let currentBox = {
            "startI": 0,
            "stopI": 0
        };

        this.boxInfo = [currentBox];

        // Find which component box each of the variables belong in,
        // while finding the bounds of that box. Top and bottom
        // rows recorded for each node in this.boxInfo[].
        for (let ri = 1; ri < this.diagNodes.length; ++ri) {
            let curNode = this.diagNodes[ri];
            let startINode = this.diagNodes[currentBox.startI];
            if (startINode.parentComponent &&
                curNode.parentComponent &&
                startINode.parentComponent === curNode.parentComponent) {
                ++currentBox.stopI;
            }
            else {
                currentBox = {
                    "startI": ri,
                    "stopI": ri
                };
            }
            this.boxInfo.push(currentBox);
        }

        // Step through this.boxInfo[] and record one set of dimensions
        // for each box in this.componentBoxInfo[].
        this.componentBoxInfo = [];
        for (let i = 0; i < this.boxInfo.length; ++i) {
            let box = this.boxInfo[i];
            if (box.startI == box.stopI) continue;
            let curNode = this.diagNodes[box.startI];
            if (!curNode.parentComponent) {
                throw "Parent component not found in box.";
            }
            box.obj = curNode.parentComponent;
            i = box.stopI;
            this.componentBoxInfo.push(box);
        }

        //do this so you save old index for the exit()
        this.gridLines = [];
        if (!this.tooMuchDetail()) {
            for (let i = 0; i < this.diagNodes.length; ++i) {
                let obj = this.diagNodes[i];
                let gl = {
                    "i": i,
                    "obj": obj
                };
                this.gridLines.push(gl);
            }
        }
    }

    /**
     * Create an SVG group for each visible element, and have the element
     * render its shape in it. Move the groups around to their correct
     * positions, providing an animated transition from the previous
     * rendering.
     */
    _drawCells() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        let selection = this.n2Groups.elements.selectAll('.n2cell')
            .data(self.visibleCells, d => d.id);

        // Use D3 to join N2MatrixCells to SVG groups, and render shapes in them.
        let gEnter = selection.enter().append('g')
            .attr('class', 'n2cell')
            .attr('transform', function (d) {
                if (self.lastClickWasLeft) {
                    let tranStr = 'translate(' +
                        (self.prevCellDims.size.width *
                            (d.col - enterIndex) +
                            self.prevCellDims.bottomRight.x) + ',' +
                        (self.prevCellDims.size.height *
                            (d.row - enterIndex) +
                            self.prevCellDims.bottomRight.y) + ')';

                    return tranStr;
                }

                let roc = (d.obj && self.findRootOfChangeFunction) ?
                    self.findRootOfChangeFunction(d.obj) : null;

                if (roc) {
                    let prevIdx = roc.prevRootIndex -
                        self.layout.zoomedElement.prevRootIndex;
                    let tranStr = 'translate(' + (self.prevCellDims.size.width * prevIdx +
                        self.prevCellDims.bottomRight.x) + ',' +
                        (self.prevCellDims.size.height * prevIdx +
                            self.prevCellDims.bottomRight.y) + ')';

                    return tranStr;
                }
                throw ('Enter transform not found');
            })
            .each(function (d) {
                // "this" refers to the element here, so leave it alone:
                d.renderer.renderPrevious(this)
                    .on('mouseover', d.mouseover())
                    .on('mousemove', d.mousemove())
                    .on('mouseleave', n2MouseFuncs.out)
                    .on('click', n2MouseFuncs.click);
            });

        gEnter.merge(selection)
            .transition(sharedTransition)
            .attr('transform', function (d) {
                let tranStr = 'translate(' + (self.cellDims.size.width * d.col +
                    self.cellDims.bottomRight.x) + ',' +
                    (self.cellDims.size.height * d.row +
                        self.cellDims.bottomRight.y) + ')';

                return (tranStr);
            })
            // "this" refers to the element here, so leave it alone:
            .each(function (d) {
                d.renderer.updateCurrent(this)
            });

        selection.exit()
            .transition(sharedTransition)
            .attr('transform', function (d) {
                if (self.lastClickWasLeft) {
                    let tranStr = 'translate(' + (self.cellDims.size.width *
                        (d.col - exitIndex) + self.cellDims.bottomRight.x) + ',' +
                        (self.cellDims.size.height * (d.row - exitIndex) +
                            self.cellDims.bottomRight.y) + ')';
                    return tranStr;
                }

                let roc = (d.obj && self.findRootOfChangeFunction) ?
                    self.findRootOfChangeFunction(d.obj) : null;

                if (roc) {
                    let index = roc.rootIndex - self.layout.zoomedElement.rootIndex;
                    return 'translate(' + (self.cellDims.size.width * index +
                        self.cellDims.bottomRight.x) + ',' +
                        (self.cellDims.size.height * index + self.cellDims.bottomRight.y) + ')';
                }
                throw ('Exit transform not found');
            })
            // "this" refers to the element here, so leave it alone:
            .each(function (d) {
                d.renderer.updateCurrent(this)
            })
            .remove();
    }

    /** Draw a line above every row in the matrix. */
    _drawHorizontalLines() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        let selection = self.n2Groups.gridlines.selectAll('.horiz_line')
            .data(self.gridLines, function (d) {
                return d.obj.id;
            });

        let gEnter = selection.enter().append('g')
            .attr('class', 'horiz_line')
            .attr('transform', function (d) {
                if (self.lastClickWasLeft) return 'translate(0,' +
                    (self.prevCellDims.size.height * (d.i - enterIndex)) + ')';
                let roc = (self.findRootOfChangeFunction) ?
                    self.findRootOfChangeFunction(d.obj) : null;
                if (roc) {
                    let index0 = roc.prevRootIndex - self.layout.zoomedElement.prevRootIndex;
                    return 'translate(0,' + (self.prevCellDims.size.height * index0) + ')';
                }
                throw ('enter transform not found');
            });
        gEnter.append('line')
            .attr('x2', self.layout.size.n2matrix.width);

        let gUpdate = gEnter.merge(selection).transition(sharedTransition)
            .attr('transform', function (d) {
                return 'translate(0,' + (self.cellDims.size.height * d.i) + ')';
            });
        gUpdate.select('line')
            .attr('x2', self.layout.size.n2matrix.width);

        selection.exit().transition(sharedTransition)
            .attr('transform', function (d) {
                if (self.lastClickWasLeft) return 'translate(0,' +
                    (self.cellDims.size.height * (d.i - exitIndex)) + ')';
                let roc = (self.findRootOfChangeFunction) ?
                    self.findRootOfChangeFunction(d.obj) : null;
                if (roc) {
                    let index = roc.rootIndex - self.layout.zoomedElement.rootIndex;
                    return 'translate(0,' + (self.cellDims.size.height * index) + ')';
                }
                throw ('exit transform not found');
            })
            .remove();
    }

    /** Draw a vertical line for every column in the matrix. */
    _drawVerticalLines() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        let selection = self.n2Groups.gridlines.selectAll(".vert_line")
            .data(self.gridLines, function (d) {
                return d.obj.id;
            });
        let gEnter = selection.enter().append("g")
            .attr("class", "vert_line")
            .attr("transform", function (d) {
                if (self.lastClickWasLeft) return "translate(" +
                    (self.prevCellDims.size.width * (d.i - enterIndex)) + ")rotate(-90)";
                let roc = (self.findRootOfChangeFunction) ? self.findRootOfChangeFunction(d.obj) : null;
                if (roc) {
                    let i0 = roc.prevRootIndex - self.layout.zoomedElement.prevRootIndex;
                    return "translate(" + (self.prevCellDims.size.width * i0) + ")rotate(-90)";
                }
                throw ("enter transform not found");
            });
        gEnter.append("line")
            .attr("x1", -self.layout.size.n2matrix.height);

        let gUpdate = gEnter.merge(selection).transition(sharedTransition)
            .attr("transform", function (d) {
                return "translate(" + (self.cellDims.size.width * d.i) + ")rotate(-90)";
            });
        gUpdate.select("line")
            .attr("x1", -self.layout.size.n2matrix.height);

        selection.exit().transition(sharedTransition)
            .attr("transform", function (d) {
                if (self.lastClickWasLeft) return "translate(" +
                    (self.cellDims.size.width * (d.i - exitIndex)) + ")rotate(-90)";
                let roc = (self.findRootOfChangeFunction) ? self.findRootOfChangeFunction(d.obj) : null;
                if (roc) {
                    let i = roc.rootIndex - self.layout.zoomedElement.rootIndex;
                    return "translate(" + (self.cellDims.size.width * i) + ")rotate(-90)";
                }
                throw ("exit transform not found");
            })
            .remove();
    }

    /** Draw boxes around the cells associated with each component. */
    _drawComponentBoxes() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        let selection = self.n2Groups.componentBoxes.selectAll(".component_box")
            .data(self.componentBoxInfo, function (d) {
                return d.obj.id;
            });
        let gEnter = selection.enter().append("g")
            .attr("class", "component_box")
            .attr("transform", function (d) {
                if (self.lastClickWasLeft) return "translate(" +
                    (self.prevCellDims.size.width * (d.startI - enterIndex)) + "," +
                    (self.prevCellDims.size.height * (d.startI - enterIndex)) + ")";
                let roc = (d.obj && self.findRootOfChangeFunction) ? self.findRootOfChangeFunction(d.obj) : null;
                if (roc) {
                    let index0 = roc.prevRootIndex - self.layout.zoomedElement.prevRootIndex;
                    return "translate(" + (self.prevCellDims.size.width * index0) + "," +
                        (self.prevCellDims.size.height * index0) + ")";
                }
                throw ("enter transform not found");
            })

        gEnter.append("rect")
            .attr("width", function (d) {
                if (self.lastClickWasLeft) return self.prevCellDims.size.width * (1 + d.stopI - d.startI);
                return self.prevCellDims.size.width;
            })
            .attr("height", function (d) {
                if (self.lastClickWasLeft) return self.prevCellDims.size.height * (1 + d.stopI - d.startI);
                return self.prevCellDims.size.height;
            });

        let gUpdate = gEnter.merge(selection).transition(sharedTransition)
            .attr("transform", function (d) {
                return "translate(" + (self.cellDims.size.width * d.startI) + "," +
                    (self.cellDims.size.height * d.startI) + ")";
            });

        gUpdate.select("rect")
            .attr("width", function (d) {
                return self.cellDims.size.width * (1 + d.stopI - d.startI);
            })
            .attr("height", function (d) {
                return self.cellDims.size.height * (1 + d.stopI - d.startI);
            });

        let nodeExit = selection.exit().transition(sharedTransition)
            .attr("transform", function (d) {
                if (self.lastClickWasLeft) return "translate(" +
                    (self.cellDims.size.width * (d.startI - exitIndex)) + "," +
                    (self.cellDims.size.height * (d.startI - exitIndex)) + ")";
                let roc = (d.obj && self.findRootOfChangeFunction) ?
                    self.findRootOfChangeFunction(d.obj) : null;
                if (roc) {
                    let index = roc.rootIndex - self.layout.zoomedElement.rootIndex;
                    return "translate(" + (self.cellDims.size.width * index) + "," +
                        (self.cellDims.size.height * index) + ")";
                }
                throw ("exit transform not found");
            })
            .remove();

        nodeExit.select("rect")
            .attr("width", function (d) {
                if (self.lastClickWasLeft) return self.cellDims.size.width * (1 + d.stopI - d.startI);
                return self.cellDims.size.width;
            })
            .attr("height", function (d) {
                if (self.lastClickWasLeft) return self.cellDims.size.height * (1 + d.stopI - d.startI);
                return self.cellDims.size.height;
            });
    }

    /** Add all the visible elements to the matrix. */
    draw() {
        startTimer('N2Matrix.draw');

        let size = this.layout.size;
        d3.select("#n2MatrixClip > rect")
            .transition(sharedTransition)
            .attr('width', size.n2matrix.width + size.svgMargin * 2)
            .attr('height', size.n2matrix.height + size.svgMargin * 2);

        this._drawCells();

        // Draw gridlines:
        if (!this.tooMuchDetail()) {
            debugInfo("Drawing gridlines.")
            this._drawHorizontalLines();
            this._drawVerticalLines();
        }
        else {
            debugInfo("Erasing gridlines.")
            this.n2Groups.gridlines.selectAll('.horiz_line').remove();
            this.n2Groups.gridlines.selectAll(".vert_line").remove();
        }
        this._drawComponentBoxes();

        stopTimer('N2Matrix.draw');

    }

    /**
     * Iterate through all the offscreen connection sets of the
     * hovered cell and draw an arrow/add a tooltip for each.
     */
    _drawOffscreenArrows(cell) {
        if (!cell.offScreen.total) return;

        for (let side in cell.offScreen) {
            for (let dir in cell.offScreen[side]) {
                for (let offscreenNode of cell.offScreen[side][dir]) {
                    this.arrowMgr.addOffGridArrow(cell.id, side, dir, {
                        'cell': {
                            'col': cell.row,
                            'row': cell.row,
                            'srcId': cell.srcObj.id,
                            'tgtId': cell.tgtObj.id
                        },
                        'matrixSize': this.diagNodes.length,
                        'label': offscreenNode.absPathName,
                        'offscreenId': offscreenNode.id
                    });
                }
            }
        }
    }

    /**
     * For a cell that's on the diagonal, look for and draw connection arrows.
     * @param {N2MatrixCell} cell The on-diagonal cell to draw arrows for.
     * @returns {Array} The highlights that can optionally be performed.
     */
    drawOnDiagonalArrows(cell) {
        // Loop over all elements in the matrix looking for other cells in the same column
        this._drawOffscreenArrows(cell);
        let highlights = [{ 'cell': cell, 'varType': 'self', 'direction': 'self' }];

        for (let col = 0; col < this.layout.visibleNodes.length; ++col) {
            if (this.exists(cell.row, col)) {
                if (col != cell.row) {
                    this.arrowMgr.addFullArrow(cell.id, {
                        'end': {
                            'col': col,
                            'row': col,
                            'id': this.grid[col][col].srcObj.id
                        },
                        'start': {
                            'col': cell.row,
                            'row': cell.row,
                            'id': cell.tgtObj.id
                        },
                        'color': N2Style.color.outputArrow,
                    });

                    highlights.push({
                        'cell': this.cell(cell.row, col),
                        'varType': 'target', 'direction': 'output'
                    });
                }
            }

            // Now swap row and col
            if (this.exists(col, cell.row)) {
                if (col != cell.row) {
                    this.arrowMgr.addFullArrow(cell.id, {
                        'start': {
                            'col': col,
                            'row': col,
                            'id': this.grid[col][col].srcObj.id
                        },
                        'end': {
                            'col': cell.row,
                            'row': cell.row,
                            'id': cell.tgtObj.id
                        },
                        'color': N2Style.color.inputArrow,
                    });

                    highlights.push({
                        'cell': this.cell(col, cell.row),
                        'varType': 'source', 'direction': 'input'
                    });
                }
            }
        }

        return highlights;
    }

    /**
     * When the mouse goes over a cell that's on the diagonal, look for and
     * draw connection arrows, and highlight variable names.
     * @param {N2MatrixCell} cell The cell the event occured on.
     */
    mouseOverOnDiagonal(cell) {
        // Don't do anything during transition:
        if (d3.active(cell)) return;
        const highlights = this.drawOnDiagonalArrows(cell);
        for (const h of highlights) h.cell.highlight(h.varType, h.direction);
    }

    drawArrowsInputView(cell, startIndex, endIndex) {
        let boxStart = this.boxInfo[startIndex];
        let boxEnd = this.boxInfo[endIndex];

        // Draw multiple horizontal lines, but no more than one vertical line
        // for box-to-box connections
        let arrows = [];
        for (let startsI = boxStart.startI; startsI <= boxStart.stopI; ++startsI) {
            for (let endsI = boxEnd.startI; endsI <= boxEnd.stopI; ++endsI) {
                if (this.exists(startsI, endsI)) {
                    arrows.push({
                        'start': startsI,
                        'end': endsI
                    });
                }
                /*
                else {
                    throw ("Doesn't exist in matrix: " + startsI + ', ' + endsI);
                } */
            }
        }

        for (let arrow of arrows) {
            this.arrowMgr.addFullArrow(cell.id, {
                'start': {
                    'col': arrow.start,
                    'row': arrow.start,
                    'id': this.grid[arrow.start][arrow.start].srcObj.id
                },
                'end': {
                    'col': arrow.end,
                    'row': arrow.end,
                    'id': this.grid[arrow.end][arrow.end].tgtObj.id
                },
                'color': (startIndex < endIndex) ?
                    N2Style.color.outputArrow : N2Style.color.inputArrow,
            });
        }
    }

    /**
     * Look for and draw cycle arrows of the specified cell.
     * @param {N2MatrixCell} cell The off-diagonal cell to draw arrows for.
     */
    drawOffDiagonalArrows(cell) {
        let src = this.diagNodes[cell.row];
        let tgt = this.diagNodes[cell.col];

        this.arrowMgr.addFullArrow(cell.id, {
            'start': {
                'col': cell.row,
                'row': cell.row,
                'id': cell.srcObj.id
            },
            'end': {
                'col': cell.col,
                'row': cell.col,
                'id': cell.tgtObj.id
            },
            'color': N2Style.color.inputArrow,
        });

        if (cell.row > cell.col) {
            let targetsWithCycleArrows = tgt.getNodesWithCycleArrows();

            for (let twca of targetsWithCycleArrows) {
                for (let ai of twca.cycleArrows) {
                    if (src.hasNode(ai.src)) {
                        for (let arrow of ai.arrows) {
                            let firstBeginIndex = -1,
                                firstEndIndex = -1;

                            // find first begin index
                            for (let mi in this.diagNodes) {
                                let rtNode = this.diagNodes[mi];
                                if (rtNode.hasNode(arrow.begin)) {
                                    firstBeginIndex = mi;
                                    break;
                                }
                            }
                            if (firstBeginIndex == -1) {
                                throw ("Error: first begin index not found");
                            }

                            // find first end index
                            for (let mi in this.diagNodes) {
                                let rtNode = this.diagNodes[mi];
                                if (rtNode.hasNode(arrow.end)) {
                                    firstEndIndex = mi;
                                    break;
                                }
                            }
                            if (firstEndIndex == -1) {
                                throw ("Error: first end index not found");
                            }

                            if (firstBeginIndex != firstEndIndex) {
                                this.drawArrowsInputView(cell, firstBeginIndex, firstEndIndex);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * When the mouse goes over a cell that's not on the diagonal, look for and
     * draw cycle arrows, and highlight variable names.
     * @param {N2MatrixCell} cell The cell the event occured on.
     */
    mouseOverOffDiagonal(cell) {
        // Don't do anything during transition:
        if (d3.active(cell)) return;

        this.drawOffDiagonalArrows(cell);

        cell.highlight('source', 'input');
        cell.highlight('target', 'output');
    }

    /**
     * Determine if a cell is on the diagonal or not and draw the appropriate
     * connection arrows.
     * @param {N2MatrixCell} cell The cell to operate on.
     */
    drawConnectionArrows(cell) {
        if (cell.row == cell.col) this.drawOnDiagonalArrows(cell);
        else this.drawOffDiagonalArrows(cell);
    }
}

</script>
     <script type="text/javascript">
/**
 * Base class for all types of N2 arrows.
 * @typedef N2Arrow
 * @prop {Number} attribs.start.row Row # of starting node
 * @prop {Number} attribs.start.col Col # of starting ndoe
 * @prop {String} attribs.start.id ID of the start node
 * @prop {Number} attribs.end.row Row # of end node (arrow points to)
 * @prop {Number} attribs.end.col Col # of end node (arrow points to)
 * @prop {String} attribs.end.id ID of the end node
 * @prop {String} color Color of the line/circle (arrowhead is black)
 * @prop {Number} width Width of the arrow path
 * @prop {Number} nodeSize.width Width of a matrix cell in pixels.
 * @prop {Number} nodeSize.height Height of a matrix cell in pixels.
 */
class N2Arrow {
    /**
     * Determine whether arrow elements already exist, and create them if not.
     * @param {Object} attribs All of the specific arrow properties.
     * @param {Object} n2Groups References to <g> SVG elements.
     * @param {Object} nodeSize The dimensions of each cell in the matrix.
     */
    constructor(attribs, n2Groups, nodeSize) {
        this.color = attribs.color;
        this.width = attribs.width;
        this.nodeSize = nodeSize;
        this.attribs = attribs;
        this._genPath = this._angledPath;

        /*
         * Generate a CSS id for the arrow. This is based on the ids of the
         * N2TreeNodes it points to rather than the cells, so if it's pinned
         * and the matrix is redrawn, we know whether to transition it. The color
         * is included because there can be identical arrows of different colors
         * stacked on each other.
         */
        this.id = 'arrow-' + attribs.start.id + '-to-'
            + attribs.end.id + '-' + this.color.replace(/#/, '');

        const existingArrow = d3.select('g#' + this.id);
        if (existingArrow.empty()) {
            debugInfo(`N2Arrow(): Creating new ${this.id}`);
            this.doTransition = false;
            this.cssClass = 'n2_hover_elements';
            this.group = n2Groups.arrows.append('g')
                .attr('id', this.id)
                .attr('class', this.cssClass)
        }
        else {
            this.doTransition = true;
            this.group = existingArrow;
            const cssClasses = String(this.group.attr('class')).split(' ');
            this.cssClass = cssClasses.find(o => o.match(/n2_hover_elements.*/));
            debugInfo(`N2Arrow(): Using existing ${this.id} with class ${this.cssClass}`);
        }
    }

    connectsToCell(cellId) {
        return (this.attribs.start.id == cellId ||
            this.attribs.end.id == cellId);
    }

    get offsetAbsX() {
        return this.nodeSize.width * N2Arrow.cellOverlap;
    }

    get offsetAbsY() {
        return this.nodeSize.height * N2Arrow.cellOverlap + 3;  // + to account for the arrow size
    }
}

N2Arrow.cellOverlap = .125;

/**
 * Draws a two-segment arrow, using provided beginning and end node locations.
 */
class N2BentArrow extends N2Arrow {
    constructor(attribs, n2Groups, nodeSize) {
        super(attribs, n2Groups, nodeSize);

        this.start = attribs.start;
        this.end = attribs.end;

        this.middle = { 'row': -1, 'col': -1 };

        this.pts = {
            'start': { 'x': -1, 'y': -1 },
            'mid': { 'x': -1, 'y': -1 },
            'end': { 'x': -1, 'y': -1 }
        }

        this._computePts();
        this.draw();
    }

    /**
     * Determine the location of the "middle" node, where the bend is. Calculate
     * the points corresponding to the associated col, row in the matrix.
     */
    _computePts() {
        this.middle.row = this.start.row;
        this.middle.col = this.end.col;
        let offsetAbsX = this.offsetAbsX;
        let offsetAbsY = this.offsetAbsY;

        this.offsetX = (this.start.col < this.end.col) ? offsetAbsX : -offsetAbsX; // Left-to-Right : Right-to-Left
        this.pts.start.x = this.nodeSize.width * this.start.col + this.nodeSize.width * .5 + this.offsetX;
        this.pts.mid.x = this.nodeSize.width * this.middle.col + this.nodeSize.width * .5;
        // this.pts.mid.x = (this.offsetX > 0)? this.nodeSize.width * this.middle.col : this.nodeSize.width * (this.middle.col + 1);
        this.pts.end.x = this.nodeSize.width * this.end.col + this.nodeSize.width * .5;

        let offsetY = (this.start.row < this.end.row) ? -offsetAbsY : offsetAbsY; // Down : Up
        this.pts.start.y = this.nodeSize.height * this.start.row + this.nodeSize.height * .5;
        this.pts.mid.y = this.nodeSize.height * this.middle.row + this.nodeSize.height * .5;
        this.pts.end.y = this.nodeSize.height * this.end.row + this.nodeSize.height * .5 + offsetY;
    }

    /** Create a path string with a quadratic curve at the bend. */
    _curvedPath() {
        const dir = (this.offsetX > 0) ? 1 : -1;
        const s = this.nodeSize.width * .5 * dir;

        return "M" + this.pts.start.x + " " + this.pts.start.y +
            " L" + this.pts.mid.x + " " + this.pts.mid.y +
            ` q${s} 0 ${s} ${s}` +
            " L" + this.pts.end.x + " " + this.pts.end.y;
    }

    /** Generate a path with a 90-degree angle at the bend. */
    _angledPath() {
        return "M" + this.pts.start.x + " " + this.pts.start.y +
            " L" + this.pts.mid.x + " " + this.pts.mid.y +
            " L" + this.pts.end.x + " " + this.pts.end.y;
    }

    /** Set up for a black/gray dot covered by a colored dot at the arrow bend. */
    _createDots() {
        this.bottomCircle = this.group.append("circle")
            .attr('id', 'bottom-circle')
            .attr("class", this.cssClass);

        this.topCircle = this.group.append("circle")
            .attr('id', 'top-circle')
            .attr("class", this.cssClass)
    }

    /** Use SVG to draw the line segments and an arrow at the end-point. */
    draw() {
        if (this.doTransition) {
            // Arrow already exists, size and/or shape needs updated
            this.path = this.group.select('path').transition(sharedTransition);

            if (this.group.classed('off-grid-arrow')) {
                // The arrow was previously going offscreen but now is fully onscreen
                this._createDots();
            }
            else {
                this.bottomCircle = this.group.select('circle#bottom-circle').transition(sharedTransition);
                this.topCircle = this.group.select('circle#top-circle').transition(sharedTransition);
            }
        }
        else {
            // This is an entirely new arrow
            this.path = this.group.append("path")
                .attr('id', 'arrow-path')
                .attr("class", this.cssClass);

            this._createDots();
        }

        this.group.classed('off-grid-arrow', false);

        this.path
            .attr("marker-end", "url(#arrow)")
            .attr('stroke-dasharray', null)
            .attr("d", this._genPath())
            .attr("fill", "none")
            .style("stroke-width", this.width)
            .style("stroke", this.color);

        this.bottomCircle
            .attr("cx", this.pts.mid.x)
            .attr("cy", this.pts.mid.y)
            .attr("r", this.width * 1.0)
            .style("stroke-width", 0)
            .style("fill-opacity", 1)
            .style("fill", N2Style.color.connection);

        this.topCircle
            .attr("cx", this.pts.mid.x)
            .attr("cy", this.pts.mid.y)
            .attr("r", this.width * 1.0)
            .style("stroke-width", 0)
            .style("fill-opacity", .75)
            .style("fill", this.color);
    }
}

/**
 * Draw a straight, dashed arrow with one side connected to an
 * offscreen node. Show a tooltip near the offscreen.
 */
class N2OffGridArrow extends N2Arrow {
    constructor(attribs, n2Groups, nodeSize) {
        super(attribs, n2Groups, nodeSize);

        this.cell = attribs.cell;

        this.label = {
            'text': attribs.label,
            'pts': {},
            'ref': null,
            'labels': {}
        }

        this.pts = {
            'start': { 'x': -1, 'y': -1 },
            'end': { 'x': -1, 'y': -1 }
        }

        /* Get the bounding rect for the N2 matrix background rect (use rect
         * because getting the bounding rect of a group doesn't work well).
         * This is used to compute the locations of the tooltips since they're divs
         * and not SVG objects.
         */
        this.bgRect = d3.select("#backgroundRect").node().getBoundingClientRect();

    }

    /** 
     * Add the pathname of the offscreen node to the label, if it's not
     * already in there. 
     * @returns {Boolean} True if the label didn't already contain the pathname.
    */
    _addToLabel() {
        let visValue = this.label.ref.style('visibility');
        let firstEntry = (!visValue.match(/visible/));
        let tipHTML = this.label.ref.node().innerHTML;

        // Prevent duplicate listings
        if (!firstEntry && tipHTML.match(this.label.text)) {
            debugInfo('Duplicate entry for label to ' + this.label.text);
            this.newLabel = false;
            return false;
        }

        this.newLabel = true;

        if (firstEntry) {
            this.label.ref
                .style('visibility', 'visible')
                .node().innerHTML = this.label.text;
        }
        else {
            this.label.ref.node().innerHTML += '<br>' + this.label.text;
        }

        // After adding the text, store the bounding rect of the label
        // so that the new position can be calculated.
        this.label.rect = this.label.ref.node().getBoundingClientRect();

        return true;
    }

    /** Put the SVG arrow on the screen and position the tooltip. */
    draw() {
        debugInfo('Adding offscreen ' + this.attribs.direction +
            ' arrow connected to ' + this.label.text);

        if (this.doTransition) {
            if (!this.group.classed('off-grid-arrow')) {
                // If it was previously a bent arrow, remove the dots.
                this.group.selectAll('circle').remove();
            }

            this.path = this.group.select('path').transition(sharedTransition);
        }
        else {
            this.path = this.group.insert('path')
                .attr('id', 'arrow-path')
                .attr('class', this.cssClass);
        }

        this.group.classed('off-grid-arrow', true);

        const mid = {
                'x': this.pts.start.x - (this.pts.start.x - this.pts.end.x)/2,
                'y': this.pts.start.y - (this.pts.start.y - this.pts.end.y)/2
            }

        this.path
            .attr('marker-end', 'url(#arrow)')
            .attr('stroke-dasharray', '5,5')
            .attr('d', `M${this.pts.start.x},${this.pts.start.y} 
                 L${mid.x},${mid.y} L${this.pts.end.x},${this.pts.end.y}`)
            .attr('fill', 'none')
            .style('stroke-width', this.width)
            .style('stroke', this.color);

        for (let pos in this.label.pts) {
            this.label.ref.style(pos, this.label.pts[pos] + 'px');
        }
    }
}

/**
 * Draw an arrow on the bottom half of the N2 matrix coming up into
 * the onscreen target cell from the offscreen source.
 */
class N2OffGridUpArrow extends N2OffGridArrow {
    constructor(attribs, n2Groups, nodeSize) {
        super(Object.assign(attribs, {
            'start': { 'id': attribs.offscreenId },
            'end': { 'id': attribs.cell.tgtId },
            'direction': 'up',
            'color': attribs.color ? attribs.color : N2Style.color.inputArrow
        }), n2Groups, nodeSize);

        this.label.ref = d3.select("div#left.offgrid");

        this._addToLabel();
        this._computePts();
        this.draw();
    }

    /**
     * Use the start coordinates and the direction of the arrow to determine
     * the starting coordinates and location of the arrowhead.
     */
    _computePts() {
        let offsetY = this.offsetAbsY;

        // Arrow
        this.pts.start.x = this.pts.end.x =
            this.nodeSize.width * this.cell.col + this.nodeSize.width * .5;
        this.pts.start.y = this.attribs.matrixSize * this.nodeSize.height +
            this.nodeSize.height * .5 + offsetY;
        this.pts.end.y = this.nodeSize.height * this.cell.row +
            this.nodeSize.height * .5 + offsetY

        // Tooltip
        if (this.newLabel) {
            this.label.pts.left = this.pts.start.x + this.bgRect.left -
                this.label.rect.width / 2;
            this.label.pts.top = this.bgRect.bottom + 2;
        }
    }
}

/**
 * Draw arrow on the top half of the N2 matrix coming down into the
 * onscreen target cell from the offscreen source.
 */
class N2OffGridDownArrow extends N2OffGridArrow {
    constructor(attribs, n2Groups, nodeSize) {
        super(Object.assign(attribs, {
            'start': { 'id': attribs.offscreenId },
            'end': { 'id': attribs.cell.tgtId },
            'direction': 'down',
            'color': attribs.color ? attribs.color : N2Style.color.inputArrow
        }), n2Groups, nodeSize);

        this.label.ref = d3.select("div#bottom.offgrid");

        this._addToLabel();
        this._computePts();
        this.draw();
    }

    /**
     * Use the start coordinates and the direction of the arrow to determine
     * the starting coordinates and location of the arrowhead.
     */
    _computePts() {
        let offsetY = this.offsetAbsY;

        // Arrow
        this.pts.start.x = this.pts.end.x =
            this.nodeSize.width * this.cell.col + this.nodeSize.width * .5;
        this.pts.start.y = this.nodeSize.height * -.5 - offsetY;
        this.pts.end.y = this.nodeSize.height * this.cell.row +
            this.nodeSize.height * .5 - offsetY;

        // Tooltip
        if (this.newLabel) {
            this.label.pts.left = this.pts.start.x + this.bgRect.left -
                this.label.rect.width / 2;
            this.label.pts.top = this.bgRect.top - this.label.rect.height - 2;
        }
    }
}

/**
 * Draw arrow on the bottom half of N2 matrix going left from the
 * onscreen source cell to the offscreen target.
 */
class N2OffGridLeftArrow extends N2OffGridArrow {
    constructor(attribs, n2Groups, nodeSize) {
        super(Object.assign(attribs, {
            'start': { 'id': attribs.cell.srcId },
            'end': { 'id': attribs.offscreenId },
            'direction': 'left',
            'color': attribs.color ? attribs.color : N2Style.color.outputArrow
        }), n2Groups, nodeSize);

        this.label.ref = d3.select("div#bottom.offgrid");

        this._addToLabel();
        this._computePts();
        this.draw();
    }

    /**
     * Use the start coordinates and the direction of the arrow to determine
     * the starting coordinates and location of the arrowhead.
     */
    _computePts() {
        let offsetX = this.offsetAbsX;

        // Arrow
        this.pts.start.y = this.pts.end.y =
            this.nodeSize.height * this.cell.row + this.nodeSize.height * .5;
        this.pts.start.x = this.nodeSize.width * this.cell.col +
            this.nodeSize.width * .5 - offsetX;
        this.pts.end.x = 0;

        // Tooltip
        if (this.newLabel) {
            this.label.pts.left = this.pts.end.x + this.bgRect.left -
                this.label.rect.width * 0.667;
            this.label.pts.top = this.pts.end.y + this.bgRect.top +
                this.label.rect.height / 2;
        }
    }
}

/**
 * Draw arrow on the top half of the N2 matrix going right away from
 * the onscreen source cell to the offscreen target.
 */
class N2OffGridRightArrow extends N2OffGridArrow {
    constructor(attribs, n2Groups, nodeSize) {
        super(Object.assign(attribs, {
            'start': { 'id': attribs.cell.srcId },
            'end': { 'id': attribs.offscreenId },
            'direction': 'right',
            'color': attribs.color ? attribs.color : N2Style.color.outputArrow
        }), n2Groups, nodeSize);

        this.label.ref = d3.select("div#right.offgrid");

        this._addToLabel();
        this._computePts();
        this.draw();
    }

    /**
     * Use the start coordinates and the direction of the arrow to determine
     * the starting coordinates and location of the arrowhead.
     */
    _computePts() {
        let offsetX = this.offsetAbsX;

        // Arrow
        this.pts.start.y = this.pts.end.y =
            this.nodeSize.height * this.cell.row + this.nodeSize.height * .5;
        this.pts.start.x = this.nodeSize.width * this.cell.col +
            this.nodeSize.width * .5 + offsetX;
        this.pts.end.x = this.attribs.matrixSize * this.nodeSize.width;

        // Tooltip
        if (this.newLabel) {
            this.label.pts.left = this.pts.end.x + this.bgRect.left -
                this.label.rect.width / 3;
            this.label.pts.top = this.pts.end.y + this.bgRect.top +
                this.label.rect.height / 2;
        }
    }
}

/**
 * Maintain a set of arrows, usually for pinning/unpinning.
 * @typedef N2ArrowCache
 * @property {Object} arrows Every individual arrow keyed by it's ID
 * @property {Object} eventCells Cells that triggered the arrows, with a Set
 *   of associated arrow IDs.
 */
class N2ArrowCache {
    /**
     * Initialize with empty cache.
     */
    constructor() {
        this.arrows = {};
        this.eventCells = {};
    }

    /**
     * Determine if the arrow exists in this cache.
     * @param {String} arrowId The ID of the arrow to look for.
     * @returns {Boolean} True if found.
     */
    hasArrow(arrowId) {
        return exists(this.arrows[arrowId]);
    }

    /**
     * Find an arrow that is pointing to or from the specified cell.
     * @param {String} cellId The ID of the cell to search for.
     * @returns {String} True if any arrow found, otherwise false.
     */
    hasCell(cellId) {
        for (const id in this.arrows) {
            if (this.arrows[id].connectsToCell(cellId)) return true;
        }

        return false;
    }

    /**
     * Add an individual arrow to the cache.
     * @param {String} cellId The ID of the cell that triggered the event.
     * @param {N2Arrow} arrow The arrow object to cache.
     * @param {Boolean} [allowReplace = true] Replacing an existing arrow is OK.
     */
    add(cellId, arrow, allowReplace = true) {
        if (this.hasArrow(arrow.id) && !allowReplace) {
            console.warn(`N2ArrowCache.add(): Not adding arrow ${arrow.id} to cache
                    since it already exists.`)
        }
        else {
            this.arrows[arrow.id] = arrow;
            this.addEventCellArrow(cellId, arrow.id);
        }
    }

    /**
     * Associate a cell with an arrow that a mouse event triggered.
     * @param {String} cellId The ID of the event-triggering cell.
     * @param {String} arrowId The ID of the arrow.
     */
    addEventCellArrow(cellId, arrowId) {
        if (!exists(this.eventCells[cellId])) this.eventCells[cellId] = new Set();
        this.eventCells[cellId].add(arrowId);
    }

    /**
     * Determine if the cell triggered any cached arrows.
     * @param {String} cellId The ID of the cell to check.
     * @returns {Boolean} True if the cellId is tracked.
     */
    hasEventCell(cellId) { return exists(this.eventCells[cellId]); }

    /**
     * Disassociate an arrow with a trigger cell. If the cell has no more arrows,
     * remove the entry.
     * @param {String} cellId The ID of the event-triggering cell.
     * @param {String} arrowId The ID of the arrow.
     */
    removeEventCellArrow(cellId, arrowId) {
        if (!exists(this.eventCells[cellId])) {
            console.warn(`removeEventCellArrow: no tracked cell with ID ${cellId}`)
        }
        else if (!this.eventCells[cellId].has(arrowId)) {
            console.warn(`removeEventCellArrow: no arrow with ID ${arrowId}
                associated with cell ID ${cellId}`)
        }
        else {
            this.eventCells[cellId].delete(arrowId)
            if (this.eventCells[cellId].size == 0) delete this.eventCells[cellId];
        }
    }

    /**
     * Delete all associations for the cell and stop tracking it.
     * @param {String} cellId The ID of the event-triggering cell.
     */
    removeEventCell(cellId) {
        if (!exists(this.eventCells[cellId])) {
            console.warn(`removeEventCellArrow: no tracked cell with ID ${cellId}`)
        }
        else {
            this.eventCells[cellId].clear();
            delete this.eventCells[cellId];
        }
    }

    /**
     * Remove drawn arrow from the screen, but keep the info cached.
     * @param {String} arrowId The ID of the single arrow to remove.
     */
    removeArrowFromScreen(arrowId) {
        if (!this.hasArrow(arrowId)) {
            console.warn(`removeArrowFromScreen: Arrow ${arrowId} doesn't exist.`)
        }
        else {
            this.arrows[arrowId].group.remove();
        }
    }

    /**
     * Remove arrow info from cache, but leave the elements on the screen.
     * @param {String} arrowId The ID of the single arrow to remove.
     */
    removeArrowFromCache(arrowId) {
        if (!this.hasArrow(arrowId)) {
            console.warn(`removeArrowFromCache: Arrow ${arrowId} doesn't exist.`)
        }
        else {
            delete this.arrows[arrowId];
            for (const cellId in this.eventCells) {
                if (this.eventCells[cellId].has(arrowId))
                    this.eventCells[cellId].delete(arrowId);
            }
        }
    }

    /**
     * Remove everything we're tracking from screen and cache.
     */
    removeAll() {
        for (const arrowId in this.arrows) {
            this.removeArrowFromScreen(arrowId);
            this.removeArrowFromCache(arrowId);
        }

        this.arrows = {};
        this.eventCells = {};
    }

    /**
     * Move an arrow from one cache to another and change its CSS classes.
     * @param {String} cellId The cell ID that triggered the event.
     * @param {String} arrowId The ID of the single arrow.
     * @param {N2ArrowCache} oldCache The cache to move the arrow from.
     * @param {String} newClassName The CSS class to add to HTML elements.
     * @param {String} oldClassName The CSS class to remove from HTML elements.
     */
    migrateArrow(cellId, arrowId, oldCache, newClassName, oldClassName) {
        const arrow = oldCache.arrows[arrowId];
        this.add(cellId, arrow);
        oldCache.removeArrowFromCache(arrowId);

        debugInfo(`migrateArrow(): Moving ${arrowId} from class ${oldClassName} to ${newClassName}`);

        arrow.cssClass = newClassName;
        arrow.group
            .classed(oldClassName, false)
            .classed(newClassName, true)
            .selectAll('.' + oldClassName)
            .classed(oldClassName, false)
            .classed(newClassName, true);
    }

    /**
     * Migrate all arrows associated with a cell into this cache from another.
     * @param {String} cellId The ID of the cell to operate on.
     * @param {N2ArrowCache} oldCache The cache to move the arrows from.
     * @param {String} newClassName The CSS class to add to HTML elements.
     * @param {String} oldClassName The CSS class to remove from HTML elements.
     */
    migrateCell(cellId, oldCache, newClassName, oldClassName) {
        if (!oldCache.hasEventCell(cellId)) {
            console.warn(`migrateCell: Event cell ${cellId} isn't tracked in
                the old cache, can't migrate arrows.`)
        }
        else {
            for (const arrowId of oldCache.eventCells[cellId]) {
                this.migrateArrow(cellId, arrowId, oldCache, newClassName, oldClassName);
            }
            delete oldCache.eventCells[cellId];
        }
    }
}

/**
 * Manage all connection arrow operations. Create new arrows, maintain
 * caches of hovered/pinned arrows, move arrows between them, and 
 * transition on updates.
 * @typedef N2ArrowManager
 * @prop {Object} n2Groups DOM elements referenced by N2Diagram
 * @prop {N2ArrowCache} hoverArrows Arrows that disappear if the mouse moves away from the cell
 * @prop {N2ArrowCache} pinnedArrows Arrows that persist and are redrawn during updates
 * @prop {Object} nodeSize Matrix cell width and height
 * @prop {Number} lineWidth Width of the arrows, calculated from nodeSize.
 * @prop {Object} arrowDirClasses The various offscreen N2Arrow derived classes.
 */
class N2ArrowManager {
    constructor(n2Groups) {
        this.n2Groups = n2Groups;
        this.hoverArrows = new N2ArrowCache();
        this.pinnedArrows = new N2ArrowCache();
        this.nodeSize = { 'width': -1, 'height': -1 };
        this._lineWidth = -1;

        this.arrowDirClasses = {
            'top': {
                'incoming': N2OffGridDownArrow,
                'outgoing': N2OffGridRightArrow
            },
            'bottom': {
                'incoming': N2OffGridUpArrow,
                'outgoing': N2OffGridLeftArrow
            }
        };
    }

    /** Make sure _lineWidth has been manually set */
    get lineWidth() {
        if (this._lineWidth < 0) {
            throw ("addFullArrow: this._lineWidth is unset")
        }

        return this._lineWidth;
    }

    /**
     * Update the node size and calculate the line width.
     * @param {Object} newNodeSize Matrix cell width and height
     */
    setNodeSize(newNodeSize) {
        this.nodeSize = newNodeSize;
        this._lineWidth = Math.min(5, newNodeSize.width * .5, newNodeSize.height * .5);
    }

    /**
     * True if the arrow is referenced in either cache
     * @param {String} arrowId The ID of the arrow to find.
     */
    arrowExists(arrowId) {
        return (this.pinnedArrows.hasArrow(arrowId) ||
            this.hoverArrows.hasArrow(arrowId));
    }

    /**
     * Create a new N2BentArrow object. This may replace existing elements
     * on the screen with new dimensions and colors. However, the arrow may
     * already exist in one of the caches, in which case it's replaced.
     * @param {String} cellId The ID of the cell that triggered the event.
     * @param {Object} attribs Values to pass to the N2Arrow constructor.
     * @returns {N2BentArrow} The newly created arrow object.
     */
    addFullArrow(cellId, attribs) {
        attribs.width = this.lineWidth;
        const newArrow = new N2BentArrow(attribs, this.n2Groups, this.nodeSize);

        // Add or replace the cache entry with the new arrow
        if (this.pinnedArrows.hasArrow(newArrow.id)) {
            this.pinnedArrows.add(cellId, newArrow);
        }
        else {
            this.hoverArrows.add(cellId, newArrow);
        }

        return newArrow;
    }

    /**
     * Create a new N2OffGridArrow-derived object. This may replace existing
     * elements on the screen with new dimensions and colors. However, the
     * arrow may already exist in one of the caches, in which case it's not
     * added again.
     * @param {String} cellId The ID of the cell that triggered the event.
     * @param {String} side Whether the arrow is in the top or bottom.
     * @param {String} dir Whether the arrow is incoming or outgoing.
     * @param {Object} attribs Values to pass to the N2Arrow constructor.
     * @returns {N2BentArrow} The newly created arrow object.
     */
    addOffGridArrow(cellId, side, dir, attribs) {
        attribs.width = this.lineWidth;
        debugInfo("addOffGridArrow(): ", side, dir, attribs)
        const newArrow = new (this.arrowDirClasses[side][dir])(attribs,
            this.n2Groups, this.nodeSize);

        // Add or replace the cache entry with the new arrow
        if (this.pinnedArrows.hasArrow(newArrow.id)) {
            this.pinnedArrows.add(cellId, newArrow);
        }
        else {
            this.hoverArrows.add(cellId, newArrow);
        }

        return newArrow;
    }

    /** 
     * Both endpoints are visible, so draw a full arrow between them.
     * @param {N2Arrow} arrow The arrow object to transition.
     * @param {N2MatrixCell} startCell Cell at the beginning of the arrow.
     * @param {N2MatrixCell} endCell Cell at the end of the arrow.
     */
    _transitionFullArrow(arrow, startCell, endCell) {
        debugInfo(`transition: Found both sides of ${arrow.id}`)
        let attribs = arrow.attribs;
        attribs.start.col = startCell.col;
        attribs.start.row = startCell.row;
        attribs.end.col = endCell.col;
        attribs.end.row = endCell.row;
        attribs.width = this.lineWidth;
        this.pinnedArrows.arrows[arrow.id] =
            new N2BentArrow(attribs, this.n2Groups, this.nodeSize);
    }

    /**
     * Only the starting cell is visible, so draw an arrow from that
     * heading offscreen in the direction the end would be.
     * @param {N2Arrow} arrow The arrow object to transition.
     * @param {N2MatrixCell} startCell Cell at the beginning of the arrow.
     * @param {N2Matrix} matrix Reference to the matrix object.
     */
    _transitionStartArrow(arrow, startCell, matrix) {
        debugInfo(`transition: Only found start cell for ${arrow.id}`)
        const side = (arrow.attribs.start.id > arrow.attribs.end.id)?
            'bottom' : 'top';
        const attribs = {
            'cell': {
                'col': startCell.col,
                'row': startCell.row,
                'srcId': startCell.srcObj.id,
                'tgtId': startCell.tgtObj.id
            },
            'width': this.lineWidth,
            'matrixSize': matrix.diagNodes.length,
            'offscreenId': arrow.attribs.end.id,
            'label': matrix.model.nodeIds[arrow.attribs.end.id].absPathName,
            'color': arrow.attribs.color
        }
        this.pinnedArrows.arrows[arrow.id] =
            new (this.arrowDirClasses[side]['outgoing'])(attribs,
                    this.n2Groups, this.nodeSize);
    }

    /**
     * Only the ending cell is visible, so draw an arrow to that
     * from offscreen in the direction the starting cell would be.
     * @param {N2Arrow} arrow The arrow object to transition.
     * @param {N2MatrixCell} endCell Cell at the end of the arrow.
     * @param {N2Matrix} matrix Reference to the matrix object.
     */
    _transitionEndArrow(arrow, endCell, matrix) {
        debugInfo(`transition: Only found end cell for ${arrow.id}`)
        const side = (arrow.attribs.start.id > arrow.attribs.end.id)?
            'bottom' : 'top';
        const attribs = {
            'cell': {
                'col': endCell.col,
                'row': endCell.row,
                'srcId': endCell.srcObj.id,
                'tgtId': endCell.tgtObj.id
            },
            'width': this.lineWidth,
            'matrixSize': matrix.diagNodes.length,
            'offscreenId': arrow.attribs.start.id,
            'label': matrix.model.nodeIds[arrow.attribs.start.id].absPathName,
            'color': arrow.attribs.color
        }
        this.pinnedArrows.arrows[arrow.id] =
            new (this.arrowDirClasses[side]['incoming'])(attribs,
                this.n2Groups, this.nodeSize);       
    }

    /**
     * Handle nodes that were uncollapsed with pinned arrows by pinning arrows
     * to their visible child nodes. This is done after the rest of the arrow
     * transitions because new arrows are added to the cache.
     * @param {Array} uncollapsedNodeIds List of nodeIds that were uncollapsed.
     * @param {N2Matrix} matrix Reference to the matrix object.
     */
    _transitionUncollapsedNodes(uncollapsedNodeIds, matrix) {
        for (const row in matrix.grid) {
            const cell = matrix.grid[row][row]; // Diagonal cells only
            for (const nodeId of uncollapsedNodeIds) {
                if (cell.obj.hasParent(matrix.model.nodeIds[nodeId])) {
                    matrix.drawOnDiagonalArrows(cell);
                    this.togglePin(cell.id, true);
                }
            }
        }
    }

    /**
     * Redraw all the visible arrows in the pinned arrow cache, and remove
     * the ones for which neither endpoint is visible. Full arrows may
     * need to transition to offgrid arrows and vice versa.
     * @param {N2Matrix} matrix The matrix to operate with.
     */
    transition(matrix) {
        let uncollapsedNodeIds = [];

        for (const arrowId in this.pinnedArrows.arrows) {
            const arrow = this.pinnedArrows.arrows[arrowId];
            const startCellInfo = matrix.findCellByNodeId(arrow.attribs.start.id);
            const endCellInfo = matrix.findCellByNodeId(arrow.attribs.end.id);
            const startCell = startCellInfo.cell;
            const endCell = endCellInfo.cell;

            if (startCell === endCell) { // Both undefined, or same cell
                if (startCell === undefined)
                    debugInfo(`transition: No visible endpoints for ${arrowId}`)
                else
                    debugInfo(`transition: ${arrowId} points to and from` +
                        ` collapsed cell ${startCell.id}`)

                this.pinnedArrows.removeArrowFromScreen(arrowId);
            }
            else if (startCellInfo.childMatch || endCellInfo.childMatch) {
                debugInfo(`transition: ${arrowId} endpoint was previously collapsed, \
                    pinning arrows for all children.`)
                if (startCellInfo.childMatch)
                    uncollapsedNodeIds.push(arrow.attribs.start.id);
                if (endCellInfo.childMatch)
                    uncollapsedNodeIds.push(arrow.attribs.end.id);

                this.pinnedArrows.removeArrowFromScreen(arrowId);
                this.pinnedArrows.removeArrowFromCache(arrowId);
            }
            else if ((startCellInfo.exactMatch || startCellInfo.parentMatch) && 
                (endCellInfo.exactMatch || endCellInfo.parentMatch)) {
                // Both endpoint cells are visible
                this._transitionFullArrow(arrow, startCell, endCell);
            }
            else if (startCell) {
                // Only the non-pointy end is visible
                this._transitionStartArrow(arrow, startCell, matrix);
            }
            else if (endCell) {
                // Only the pointy end is visible
                this._transitionEndArrow(arrow, endCell, matrix);
            }
        }

        // Adding arrows, so do after iteration through arrow list
        this._transitionUncollapsedNodes(uncollapsedNodeIds, matrix);
    }

    /**
     * If arrows are hovering, then pin them, and vice versa.
     * @param {String} cellId The ID of the N2MatrixCell to operate on.
     * @param {Boolean} [ pinOnly = false] If true, don't unpin anything.
     */
    togglePin(cellId, pinOnly = false) {
        const cellClassName = "n2_hover_elements_" + cellId;
        if (this.pinnedArrows.hasEventCell(cellId)) { // Arrows already pinned
            if (pinOnly) return;
            debugInfo(`Unpinning ${cellId} arrows`)
            this.hoverArrows.migrateCell(cellId, this.pinnedArrows,
                'n2_hover_elements', cellClassName);
            this.removeAllHovered();
        }
        else if (this.hoverArrows.hasEventCell(cellId)) { // Arrows just "hovered"
            debugInfo(`Pinning ${cellId} arrows`)
            this.pinnedArrows.migrateCell(cellId, this.hoverArrows,
                cellClassName, 'n2_hover_elements');
        }
        else {
            console.warn(`togglePin(): No known arrows for cell ${cellId}.`);
        }
    }

    /** Remove all arrows in the hoverArrow cache */
    removeAllHovered() {
        const removedArrowIds = Object.keys(this.hoverArrows.arrows);
        this.hoverArrows.removeAll();
        debugInfo(`removeAllHovered(): Removed ${removedArrowIds.length} arrows`)
    }

    /** Remove all arrows in the pinnedArrow cache */
    removeAllPinned() {
        const removedArrowIds = Object.keys(this.pinnedArrows.arrows);
        this.pinnedArrows.removeAll();
        debugInfo(`removeAllPinned(): Removed ${removedArrowIds.length} arrows`)
    }
}

</script>

    <script type="text/javascript">
/**
 * Manage the search functions for N2, which uses the Awesomplete widget from
 * https://leaverou.github.io/awesomplete/
 * @typedef N2Search
 */
class N2Search {
    /**
     * Initialize N2Search object properties and Awesomeplete.
     * @param {N2TreeNode} zoomedElement The selected node in the model tree.
     * @param {N2TreeNode} root The base element of the model tree.
     */
    constructor(zoomedElement, root) {
        // Used for autocomplete suggestions:
        this.filteredWord = {
            'value': "",
            'containsDot': false,
            'baseName': ""

        }
        this.filterSet = {};

        this.updateRecomputesAutoComplete = true;

        this.wordIndex = 0;
        this.searchVals = [];
        this.inDataFunction = true;

        this.searchCollapsedUndo = []; // Non-matching nodes to be minimized/hidden.

        this.numMatches = 0;
        this.searchInputDiv = d3.select("#awesompleteId").node();
        this.searchCountDiv = d3.select("#searchCountId");

        this._setupAwesomplete();
        this._addEventListeners();
        this.update(zoomedElement, root);
    }

    /** Initialize the Awesomplete widget. */
    _setupAwesomplete() {
        let self = this;
        this.searchAwesomplete = new Awesomplete(self.searchInputDiv, {
            "minChars": 1,
            "maxItems": 15,
            "list": [],
            "filter": function(text, input) {
                if (self.inDataFunction) {
                    self.inDataFunction = false;
                    self.filterSet = {};
                }

                if (self.filteredWord.value.length == 0) return false;

                if (self.filterSet.hasOwnProperty(text)) return false;

                self.filterSet[text] = true;

                if (self.filteredWord.containsDot)
                    return Awesomplete.FILTER_STARTSWITH(text,
                        self.filteredWord.value);

                return Awesomplete.FILTER_CONTAINS(text,
                    self.filteredWord.value);
            },
            "item": function(text, input) {
                return Awesomplete.ITEM(text, self.filteredWord.value);
            },
            "replace": function(text) {
                let newVal = "";
                let cursorPos = 0;
                for (let i = 0; i < self.searchVals.length; ++i) {
                    newVal += ((i == self.wordIndex) ? text : self.searchVals[i]) + " ";
                    if (i == self.wordIndex) cursorPos = newVal.length - 1;
                }
                this.input.value = newVal;
                self.searchInputDiv.setSelectionRange(cursorPos, cursorPos);
            },
            "data": function(item /*, input*/ ) {
                self.inDataFunction = true;
                if (self.filteredWord.containsDot) {
                    let baseIndex = item.toLowerCase().indexOf("." +
                        self.filteredWord.baseName.toLowerCase() + ".");
                    if (baseIndex > 0) return item.slice(baseIndex + 1);
                }
                return item;
            }
        });
    }

    /**
     * Add a couple of event listeners that are easier to do from here
     * than in N2UserInterface.
     */
    _addEventListeners() {
        let self = this;

       d3.select('body').on('awesomplete-selectcomplete', function() {
           self.searchInputEventListener();
           self.searchAwesomplete.evaluate();
       });

       d3.select('body').on('input', this.searchInputEventListener.bind(this));
    }

    /**
     * Recurse through the tree and find nodes with pathnames that match
     * the computed regular expression. Minimize/hide nodes that don't match.
     * @param {N2TreeNode} node The current node to operate on.
     * @param {RegExp} regexMatch A regular expression assembled from the search values.
     * @param {Array} undoList List of nodes that have been hidden/minimized.
     * @returns {Boolean} True if a match was found, false otherwise.
     */
    _doSearch(node, regexMatch, undoList) {
        let didMatch = false;

        if (node.hasChildren() && !node.isMinimized) {
            // depth first, dont go into minimized children
            for (let child of node.children) {
                if (this._doSearch(child, regexMatch, undoList)) didMatch = true;
            }
        }

        if (node === this.zoomedElement) return didMatch;

        if (!didMatch && !node.hasChildren() && node.isInputOrOutput()) {
            didMatch = regexMatch.test(node.absPathName);
            if (didMatch) {
                // only inputs and outputs can count as matches
                ++this.numMatches;
            }
            else if (undoList) {
                // did not match and undo list is not null
                node.varIsHidden = true;
                undoList.push(node);
            }
        }

        if (!didMatch && node.hasChildren() && !node.isMinimized && undoList) {
            // minimizeable and undoList not null
            node.isMinimized = true;
            undoList.push(node);
        }

        return didMatch;
    }

    /**
     * Reset the number of matches to zero and execute the search with a null value
     * for undoList, so it's not changed.
     */
    _countMatches() {
        this.numMatches = 0;

        if (this.searchVals.length != 0)
            this._doSearch(this.zoomedElement, this._getSearchRegExp(this.searchVals), null);
    }

    /** Undo results of the previous search, and perform a new one. */
    performSearch() {
        for (let node of this.searchCollapsedUndo) {
            //auto undo on successive searches
            if (!node.hasChildren() && node.isInputOrOutput()) node.varIsHidden = false;
            else node.isMinimized = false;
        }

        this.numMatches = 0;
        this.searchCollapsedUndo = [];
        if (this.searchVals.length != 0)
            this._doSearch(this.zoomedElement, this._getSearchRegExp(this.searchVals),
                this.searchCollapsedUndo);

    }

    /** Do some escaping and replacing of globbing with regular expressions. */
    _getSearchRegExp(searchValsArray) {
        let regexStr = new String("(^" + searchValsArray.join("$|^") + "$)")
            .replace(/\./g, "\\.") //convert . to regex
            .replace(/\?/g, ".") //convert ? to regex
            .replace(/\*/g, ".*?") //convert * to regex
            .replace(/\^/g, "^.*?"); //prepend *

        return new RegExp(regexStr, "i"); // case insensitive
    }

    _isValid(value) {
        return value.length > 0;
    }

    /**
     * React to each value entered into the search input box.
     * @param {Event} e The object describing the keypress event.
     */
    searchInputEventListener() {
        testThis(this, 'N2Search', 'searchInputEventListener');

        let target = d3.event.target;
        if (target.id != "awesompleteId") return;

        //valid characters AlphaNumeric : _ ? * space .
        let newVal = target.value.replace(/([^a-zA-Z0-9:_\?\*\s\.])/g, "");

        if (newVal != target.value) {
            target.value = newVal; // won't trigger new event
        }

        this.searchVals = target.value.split(" ");

        let filtered = this.searchVals.filter(this._isValid);
        this.searchVals = filtered;

        let lastLetterTypedIndex = target.selectionStart - 1;

        let endIndex = target.value.indexOf(" ", lastLetterTypedIndex);
        if (endIndex == -1) endIndex = target.value.length;

        let startIndex = target.value.lastIndexOf(" ", lastLetterTypedIndex);
        if (startIndex == -1) startIndex = 0;

        let sub = target.value.substring(startIndex, endIndex).trim();
        // valid openmdao character types: AlphaNumeric : _ .
        this.filteredWord.value = sub.replace(/([^a-zA-Z0-9:_\.])/g, "");

        let i = 0;
        for (let val of this.searchVals) {
            if (val.replace(/([^a-zA-Z0-9:_\.])/g, "") == this.filteredWord.value) {
                this.wordIndex = i;
                break;
            }
            ++i;
        }

        this.filteredWord.containsDot = (this.filteredWord.value.indexOf(".") != -1);
        this.searchAwesomplete.list = this.filteredWord.containsDot ?
            this.autoComplete.paths.list : this.autoComplete.names.list;
        this.filteredWord.baseName = this.filteredWord.containsDot ?
            this.filteredWord.value.split(".")[0].trim() : "";

        this._countMatches();
        this.searchCountDiv.html("" + this.numMatches + " matches");
    }

    /**
     * Find the earliest minimized parent of the specified node.
     * @param {N2TreeNode} node The node to search from.
     * @returns {N2TreeNode} The earliest mimimized parent node.
     */
    findRootOfChangeForSearch(node) {
        let earliestObj = node;
        for (let obj = node; obj != null; obj = obj.parent) {
            if (obj.isMinimized) earliestObj = obj;
        }
        return earliestObj;
    }

    /**
     * Recurse through the children of the node and add their names to the
     * autocomplete list of names, if they're not already in it.
     * @param {N2TreeNode} node The node to search from.
     */
    _populateAutoCompleteList(node) {
        if (node.hasChildren() && !node.isMinimized) {
            // Depth first, dont go into minimized children
            for (let child of node.children) {
                this._populateAutoCompleteList(child);
            }
        }

        if (node === this.zoomedElement) return;

        let nodeName = node.name;
        if (! node.isInputOrOutput()) nodeName += ".";
        let namesToAdd = [nodeName];

        for (let name of namesToAdd) {
            if (!this.autoComplete.names.set.hasOwnProperty(name)) {
                this.autoComplete.names.set[name] = true;
                this.autoComplete.names.list.push(name);
            }
        }

        let localPathName = (this.zoomedElement === this.modelRoot) ?
            node.absPathName : node.absPathName.slice(this.zoomedElement.absPathName.length + 1);

        if (!this.autoComplete.paths.set.hasOwnProperty(localPathName)) {
            this.autoComplete.paths.set[localPathName] = true;
            this.autoComplete.paths.list.push(localPathName);
        }
    }

    /**
     * If the zoomed element has changed, update the auto complete lists.
     * @param {N2TreeNode} zoomedElement The selected node in the model tree.
     * @param {N2TreeNode} root The base element of the model tree.
     */
    update(zoomedElement, root) {
        this.zoomedElement = zoomedElement;
        this.modelRoot = root;

        if (!this.updateRecomputesAutoComplete) {
            this.updateRecomputesAutoComplete = true;
            return;
        }

        this.autoComplete = {
            'names': {
                'list': [],
                'set': {}
            },
            'paths': {
                'list': [],
                'set': {}
            }
        }

        this._populateAutoCompleteList(this.zoomedElement);
    }
}

</script>
     <script type="text/javascript">
/**
 * Base class for toolbar button events. Show, hide, or
 * move the tool tip box.
 * @typedef N2ToolbarButtonNoClick
 * @property {Object} tooltipBox A reference to the tool-tip element.
 * @property {Array} tooltips One or two tooltips to display.
 * @property {Object} toolbarButton A reference to the toolbar button.
 */
class N2ToolbarButtonNoClick {
    /**
     * Set up the event handlers.
     * @param {String} id A selector for the button element.
     * @param {Object} tooltipBox A reference to the tool-tip element.
     * @param {String} tooptipText Content to fill the tool-tip box with.
     */
    constructor(id, tooltipBox, tooltipText) {
        this.tooltips = [tooltipText];

        this.toolbarButton = d3.select(id);
        this.tooltipBox = tooltipBox;

        this.toolbarButton
            .on("mouseover", this.mouseOver.bind(this))
            .on("mouseleave", this.mouseLeave.bind(this))
            .on("mousemove", this.mouseMove.bind(this));
    }

    /** When the mouse enters the element, show the tool tip */
    mouseOver() {
        this.tooltipBox
            .text(this.tooltips[0])
            .style("visibility", "visible");
    }

    /** When the mouse leaves the element, hide the tool tip */
    mouseLeave() {
        this.tooltipBox.style("visibility", "hidden");
    }

    /** Keep the tool-tip near the mouse */
    mouseMove() {
        this.tooltipBox.style("top", (d3.event.pageY - 30) + "px")
            .style("left", (d3.event.pageX + 5) + "px");
    }
}

/**
 * Manage clickable toolbar buttons
 * @typedef N2ToolbarButtonClick
 * @property {Object} tooltipBox A reference to the tool-tip element.
 * @property {Array} tooltips One or two tooltips to display.
 * @property {Object} toolbarButton A reference to the toolbar button.
 * @property {Function} clickFn The function to call when clicked.
 */
class N2ToolbarButtonClick extends N2ToolbarButtonNoClick {
    /**
     * Set up the event handlers.
     * @param {String} id A selector for the button element.
     * @param {Object} tooltipBox A reference to the tool-tip element.
     * @param {String} tooptipText Content to fill the tool-tip box with.
     * @param {Function} clickFn The function to call when clicked.
     */
    constructor(id, tooltipBox, tooltipText, clickFn) {
        super(id, tooltipBox, tooltipText);
        this.clickFn = clickFn;

        let self = this;

        this.toolbarButton.on('click', function () { self.click(this); });
    }

    /**
     * Defined separately so the derived class can override
     * @param {Object} target Reference to the HTML element that was clicked
     */
    click(target) {
        this.clickFn(target);
    }
}

/**
 * Manage toolbar buttons that alternate states when clicked.
 * @typedef N2ToolbarButtonToggle
 * @property {Object} tooltipBox A reference to the tool-tip element.
 * @property {Array} tooltips One or two tooltips to display.
 * @property {Object} toolbarButton A reference to the toolbar button.
 * @property {Function} clickFn The function to call when clicked.
 * @property {Function} predicateFn Function returning a boolean representing the state.
 */
class N2ToolbarButtonToggle extends N2ToolbarButtonClick {
    /**
     * Set up the event handlers.
     * @param {String} id A selector for the button element.
     * @param {Object} tooltipBox A reference to the tool-tip element.
     * @param {String} tooptipTextArr A pair of tooltips for alternate states.
     * @param {Function} predicateFn Function returning a boolean representing the state.
     * @param {Function} clickFn The function to call when clicked.
     */
    constructor(id, tooltipBox, tooltipTextArr, predicateFn, clickFn) {
        super(id, tooltipBox, tooltipTextArr[0], clickFn);
        this.tooltips.push(tooltipTextArr[1]);
        this.predicateFn = predicateFn;
    }

    /**
     * When the mouse enters the element, show a tool tip based
     * on the result of the predicate function.
     */
    mouseOver() {
        this.tooltipBox
            .text(this.predicateFn() ? this.tooltips[0] : this.tooltips[1])
            .style("visibility", "visible");
    }

    /**
     * When clicked, perform the associated function, then change the tool tip
     * based on the result of the predicate function.
     * @param {Object} target Reference to the HTML element that was clicked
     */
    click(target) {
        this.clickFn(target);

        this.tooltipBox
            .text(this.predicateFn() ? this.tooltips[0] : this.tooltips[1])
            .style("visibility", "visible");

    }
}

/**
 * Manage the set of buttons and tools at the left of the diagram.
 * @typedef N2Toolbar
 * @property {Boolean} hidden Whether the toolbar is visible or not.
 */
class N2Toolbar {
    /**
     * Set up the event handlers for mouse hovering and clicking.
     * @param {N2UserInterface} n2ui Reference to the main interface object
     * @param {Number} sliderHeight The maximum height of the n2
     */
    constructor(n2ui, sliderHeight = window.innerHeight * .95) {
        const self = this;

        this.toolbarContainer = d3.select('#toolbarLoc');
        this.toolbar = d3.select('#true-toolbar');
        this.hideToolbarButton = d3.select('.toolbar-hide-container');
        this.hideToolbarIcon = this.hideToolbarButton.select('i');
        this.searchBar = d3.select('#awesompleteId');
        this.searchCount = d3.select('#searchCountId');

        this.hidden = true;

        // Display toolbar if not embedded, or if embedded doc location
        // href include the #toolbar anchor
        if (!EMBEDDED || (EMBEDDED && window.location.href.includes('#toolbar')))
            this.show();

        this._setupButtonFunctions(n2ui);

        // Expand the search bar and set focus when search button clicked
        d3.select('#searchbar-container').on('click', function () {
            self.searchCount.html('0 matches');
            
            self.searchBar.node().value = '';
            d3.select('#searchbar-and-label').attr('class', 'searchbar-visible');

            // This is necessary rather than just calling focus() due to the
            // transition animation
            window.setTimeout(function () {
                self.searchBar.node().focus();
            }, 200);
        });

        // Retract search bar when focus is lost
        this.searchBar.on('focusout', function () {
            d3.select('#searchbar-and-label').attr('class', 'searchbar-hidden')
        });
    }

    /** Slide everything to the left offscreen 75px, rotate the button */
    hide() {
        this.toolbarContainer.style('left', '-65px');
        this.hideToolbarButton.style('left', '-20px');
        this.hideToolbarIcon.style('transform', 'rotate(-180deg)');
        d3.select('#d3_content_div').style('margin-left', '-65px');
        this.hidden = true;
    }

    /** Slide everything to the right and rotate the button */
    show() {
        this.hideToolbarIcon.style('transform', 'rotate(0deg)');
        this.toolbarContainer.style('left', '0px');
        this.hideToolbarButton.style('left', '45px');
        d3.select('#d3_content_div').style('margin-left', '0px');
        this.hidden = false;
    }

    toggle() {
        if (this.hidden) this.show();
        else this.hide();
    }

    /** When an expanded button is clicked, update the 'root' button to the same icon/function. */
    _setRootButton(clickedNode) {
        let container = d3.select(clickedNode.parentNode.parentNode);
        let button = d3.select(clickedNode);
        let rootButton = container.select('i');

        rootButton
            .attr('class', button.attr('class'))
            .attr('id', button.attr('id'))
            .node().onclick = button.node().onclick;
    }

    /**
     * Associate all of the buttons on the toolbar with a method in N2UserInterface.
     * @param {N2UserInterface} n2ui A reference to the UI object 
     */
    _setupButtonFunctions(n2ui) {
        const self = this; // For callbacks that change "this". Alternative to using .bind().
        const tooltipBox = d3.select(".tool-tip");

        new N2ToolbarButtonClick('#reset-graph', tooltipBox,
            "View entire model starting from root", e => { n2ui.homeButtonClick(); });

        new N2ToolbarButtonClick('#undo-graph', tooltipBox,
            "Move back in view history", e => { n2ui.backButtonPressed() });

        new N2ToolbarButtonClick('#redo-graph', tooltipBox,
            "Move forward in view history", e => { n2ui.forwardButtonPressed() });

        new N2ToolbarButtonClick('#collapse-element', tooltipBox,
            "Control variable collapsing",
            e => { n2ui.collapseAll(n2ui.n2Diag.zoomedElement) });

        new N2ToolbarButtonClick('#collapse-element-2', tooltipBox,
            "Collapse only variables in current view",
            function (target) {
                n2ui.collapseAll(n2ui.n2Diag.zoomedElement);
                self._setRootButton(target);
            });

        new N2ToolbarButtonClick('#collapse-all', tooltipBox,
            "Collapse all variables in entire model",
            function (target) {
                n2ui.collapseAll(n2ui.n2Diag.model.root);
                self._setRootButton(target);
            });

        new N2ToolbarButtonClick('#expand-element', tooltipBox,
            "Expand only variables in current view",
            function (target) {
                n2ui.expandAll(n2ui.n2Diag.zoomedElement);
                self._setRootButton(target);
            });

        new N2ToolbarButtonClick('#expand-all', tooltipBox,
            "Expand all variables in entire model",
            function (target) {
                n2ui.expandAll(n2ui.n2Diag.model.root);
                self._setRootButton(target);
            });

        new N2ToolbarButtonClick('#hide-connections', tooltipBox,
            "Remove all connection arrows",
            function (target) {
                n2ui.n2Diag.clearArrows();
                self._setRootButton(target);
            });

        new N2ToolbarButtonClick('#hide-connections-2', tooltipBox,
            "Remove all connection arrows",
            function (target) {
                n2ui.n2Diag.clearArrows();
                self._setRootButton(target);
            });

        new N2ToolbarButtonClick('#show-all-connections', tooltipBox,
            "Show all connections in view",
            function (target) {
                n2ui.n2Diag.showAllArrows();
                self._setRootButton(target);
            });

        new N2ToolbarButtonToggle('#linear-solver-button', tooltipBox,
            ["Show non-linear solvers", "Show linear solvers"],
            pred => { return !n2ui.n2Diag.showLinearSolverNames; },
            e => { n2ui.toggleSolverNamesCheckboxChange(); }
        );

        new N2ToolbarButtonToggle('#legend-button', tooltipBox,
            ["Show legend", "Hide legend"],
            pred => { return n2ui.legend.hidden; },
            e => { n2ui.toggleLegend(); }
        );

        new N2ToolbarButtonNoClick('#text-slider-button', tooltipBox, "Set text height");
        new N2ToolbarButtonNoClick('#depth-slider-button', tooltipBox, "Set collapse depth");
        new N2ToolbarButtonNoClick('#model-slider-button', tooltipBox, "Set model height");

        new N2ToolbarButtonClick('#save-button', tooltipBox,
            "Save to SVG", e => { n2ui.n2Diag.saveSvg() });

        new N2ToolbarButtonToggle('#info-button', tooltipBox,
            ["Show detailed node information", "Hide detailed node information"],
            pred => { return n2ui.nodeInfoBox.hidden; },
            e => {
                n2ui.nodeInfoBox.unpin();
                n2ui.nodeInfoBox.clear();
                n2ui.nodeInfoBox.toggle();
            }
        );

        new N2ToolbarButtonToggle('#question-button', tooltipBox,
            ["Hide N2 diagram help", "Show N2 diagram help"],
            pred => { return d3.select("#myModal").style('display') == "block"; },
            DisplayModal
        );

        new N2ToolbarButtonToggle('#hide-toolbar', tooltipBox,
            ["Show toolbar", "Hide toolbar"],
            pred => { return self.hidden },
            e => { self.toggle() }
        );

        // The font size slider is a range input
        this.toolbar.select('#text-slider').on('input', function () {
            const fontSize = this.value;
            n2ui.n2Diag.fontSizeSelectChange(fontSize);

            const fontSizeIndicator = self.toolbar.select('#font-size-indicator');
            fontSizeIndicator.html(fontSize + ' px');
        });

        // The model height slider is a range input
        this.toolbar.select('#model-slider')
            .on('input', function () {
                d3.select('#model-slider-label').html(this.value + "%");
            })
            .on('mouseup', function () {
                n2ui.n2Diag.manuallyResized = true;
                const modelHeight = window.innerHeight * (parseInt(this.value) / 100);
                n2ui.n2Diag.verticalResize(modelHeight);
                const gapSpace = (n2ui.n2Diag.dims.size.partitionTreeGap - 3) +
                    n2ui.n2Diag.dims.size.unit;
            });

        this.toolbar.select('#model-slider-fit')
            .on('click', function () {
                n2ui.n2Diag.manuallyResized = false;
                d3.select('#model-slider').node().value = '95';
                d3.select('#model-slider-label').html("95%")
                n2ui.n2Diag.verticalResize(window.innerHeight * .95);

                const gapSpace = (n2ui.n2Diag.dims.size.partitionTreeGap - 3) +
                    n2ui.n2Diag.dims.size.unit;
            })
    }
}

</script>
     <script type="text/javascript">
/**
 * Manage all components of the application. The model data, the CSS styles, the
 * user interface, the layout of the N2 matrix, and the N2 matrix grid itself are
 * all member objects.
 * @typedef N2Diagram
 * @property {ModelData} model Processed model data received from Python.
 * @property {N2Style} style Manages N2-related styles and functions.
 * @property {N2Layout} layout Sizes and positions of visible elements.
 * @property {N2Matrix} matrix Manages the grid of visible model parameters.
 * @property {N2TreeNode} zoomedElement The element the diagram is currently based on.
 * @property {N2TreeNode} zoomedElementPrev Reference to last zoomedElement.
 * @property {Object} dom Container for references to web page elements.
 * @property {Object} dom.parentDiv The outermost div we work with.
 * @property {Object} dom.d3ContentDiv The div containing all of the diagram's content.
 * @property {Object} dom.svgDiv The div containing the SVG element.
 * @property {Object} dom.svg The SVG element.
 * @property {Object} dom.svgStyle Object where SVG style changes can be made.
 * @property {Object} dom.toolTip Div to display tooltips.
 * @property {Object} dom.n2OuterGroup The outermost div of N2 itself.
 * @property {Object} dom.n2Groups References to <g> SVG elements.
 * @property {Boolean} showPath If we're currently displaying the path of the zoomed element.
 * @property {number} chosenCollapseDepth The selected depth from the drop-down.
 * @property {Object} scales Scalers in the X and Y directions to associate the relative
 *   position of an element to actual pixel coordinates.
 * @property {Object} transitCoords
 */
class N2Diagram {
    constructor(modelJSON) {
        this.modelData = modelJSON;
        this.model = new ModelData(modelJSON);
        this.zoomedElement = this.zoomedElementPrev = this.model.root;
        this.showPath = false;
        this.manuallyResized = false; // If the diagram has been sized by the user

        // Assign this way because defaultDims is read-only.
        this.dims = JSON.parse(JSON.stringify(defaultDims));

        this._referenceD3Elements();
        this.transitionStartDelay = N2TransitionDefaults.startDelay;
        this.chosenCollapseDepth = -1;
        this.showLinearSolverNames = true;

        this.style = new N2Style(this.dom.svgStyle, this.dims.size.font);
        this.layout = new N2Layout(this.model, this.zoomedElement,
            this.showLinearSolverNames, this.dims);
        this.search = new N2Search(this.zoomedElement, this.model.root);
        this.ui = new N2UserInterface(this);
        // Keep track of arrows to show and hide them
        this.arrowMgr = new N2ArrowManager(this.dom.n2Groups);
        this.matrix = new N2Matrix(this.model, this.layout, this.dom.n2Groups,
            this.arrowMgr, true, this.ui.findRootOfChangeFunction);

        // TODO: Move to N2Layout
        this.scales = {
            'unit': 'px',
            'model': {
                'x': d3.scaleLinear().range([0, this.layout.size.partitionTree.width]),
                'y': d3.scaleLinear().range([0, this.layout.size.partitionTree.height])
            },
            'solver': {
                'x': d3.scaleLinear().range([0, this.layout.size.solverTree.width]),
                'y': d3.scaleLinear().range([0, this.layout.size.solverTree.height])
            },
            'firstRun': true
        }

        // TODO: Move to N2Layout
        this.prevScales = {
            'model': {
                'x': null,
                'y': null
            },
            'solver': {
                'x': null,
                'y': null
            },
        };

        this.transitCoords = {
            'unit': 'px',
            'model': {
                'x': 0,
                'y': 0
            },
            'solver': {
                'x': 0,
                'y': 0
            }
        };

        this.prevTransitCoords = {
            'unit': 'px',
            'model': {
                'x': 0,
                'y': 0
            },
            'solver': {
                'x': 0,
                'y': 0
            }
        };
    }

    /**
     * Switch back and forth between showing the linear or non-linear solver names. 
     */
    toggleSolverNameType() {
        this.showLinearSolverNames = !this.showLinearSolverNames;
    }

    /**
     * Save the SVG to a filename selected by the user.
     * TODO: Use a proper file dialog instead of a simple prompt.
     */
    saveSvg() {
        let svgData = this.dom.svg.node().outerHTML;

        // Add name spaces.
        if (!svgData.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)) {
            svgData = svgData.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
        }
        if (!svgData.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)) {
            svgData = svgData.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
        }

        // Add XML declaration
        svgData = '<?xml version="1.0" standalone="no"?>\r\n' + svgData;

        svgData = vkbeautify.xml(svgData);
        let svgBlob = new Blob([svgData], {
            type: "image/svg+xml;charset=utf-8"
        });
        let svgUrl = URL.createObjectURL(svgBlob);
        let downloadLink = document.createElement("a");
        downloadLink.href = svgUrl;
        let svgFileName = prompt("Filename to save SVG as", 'partition_tree_n2.svg');
        downloadLink.download = svgFileName;
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
    }

    /**
     * Replace the current zoomedElement, but preserve its value.
     * @param {Object} newZoomedElement Replacement zoomed element.
     */
    updateZoomedElement(newZoomedElement) {
        this.zoomedElementPrev = this.zoomedElement;
        this.zoomedElement = newZoomedElement;
        this.layout.zoomedElement = this.zoomedElement;
    }

    /** 
     * Setup internal references to D3 objects so we can avoid running
     * d3.select() over and over later.
     */
    _referenceD3Elements() {
        this.dom = {
            'parentDiv': document.getElementById("ptN2ContentDivId"),
            'd3ContentDiv': parentDiv.querySelector("#d3_content_div"),
            'svgDiv': d3.select("#svgDiv"),
            'svg': d3.select("#svgId"),
            'svgStyle': d3.select("#svgId style"),
            'toolTip': d3.select(".tool-tip"),
            'arrowMarker': d3.select("#arrow"),
            'n2OuterGroup': d3.select('g#n2outer'),
            'n2InnerGroup': d3.select('g#n2inner'),
            'pTreeGroup': d3.select('g#tree'),
            'highlightBar': d3.select('g#highlight-bar'),
            'pSolverTreeGroup': d3.select('g#solver_tree'),
            'n2BackgroundRect': d3.select('g#n2inner rect'),
            'waiter': d3.select('#waiting-container'),
            'clips': {
                'partitionTree': d3.select("#partitionTreeClip > rect"),
                'n2Matrix': d3.select("#n2MatrixClip > rect"),
                'solverTree': d3.select("#solverTreeClip > rect")
            },

        };

        let n2Groups = {};
        this.dom.n2InnerGroup.selectAll('g').each(function () {
            const d3elem = d3.select(this);
            const name = new String(d3elem.attr('id')).replace(/n2/, '');
            n2Groups[name] = d3elem;
        })
        this.dom.n2Groups = n2Groups;

        let offgrid = {};
        this.dom.n2OuterGroup.selectAll('g.offgridLabel').each(function () {
            const d3elem = d3.select(this);
            const name = new String(d3elem.attr('id')).replace(/n2/, '');
            offgrid[name] = d3elem;
        })
        this.dom.n2Groups.offgrid = offgrid;


    }

    /**
     * Make a copy of the previous transit coordinates and linear scalers before
     * setting new ones.
     * TODO: Move to N2Layout
     */
    _preservePreviousScale() {
        // Preserve previous coordinates
        Object.assign(this.prevTransitCoords.model, this.transitCoords.model);
        Object.assign(this.prevTransitCoords.solver, this.transitCoords.solver);

        // Preserve previous linear scales
        this.prevScales.model.x = this.scales.model.x.copy();
        this.prevScales.model.y = this.scales.model.y.copy();
        this.prevScales.solver.x = this.scales.solver.x.copy();
        this.prevScales.solver.y = this.scales.solver.y.copy();
    }

    // TODO: Move to N2Layout
    _updateScale() {
        if (!this.scales.firstRun) this._preservePreviousScale();

        this.transitCoords.model.x = (this.zoomedElement.dims.x ?
            this.layout.size.partitionTree.width - this.layout.size.parentNodeWidth :
            this.layout.size.partitionTree.width) / (1 - this.zoomedElement.dims.x);
        this.transitCoords.model.y = this.layout.size.partitionTree.height /
            this.zoomedElement.dims.height;

        this.scales.model.x
            .domain([this.zoomedElement.dims.x, 1])
            .range([this.zoomedElement.dims.x ? this.layout.size.parentNodeWidth : 0,
            this.layout.size.partitionTree.width
            ]);
        this.scales.model.y
            .domain([this.zoomedElement.dims.y, this.zoomedElement.dims.y +
                this.zoomedElement.dims.height
            ])
            .range([0, this.layout.size.partitionTree.height]);

        this.transitCoords.solver.x = (this.zoomedElement.solverDims.x ?
            this.layout.size.solverTree.width - this.layout.size.parentNodeWidth :
            this.layout.size.solverTree.width) / (1 - this.zoomedElement.solverDims.x);
        this.transitCoords.solver.y = this.layout.size.solverTree.height /
            this.zoomedElement.solverDims.height;

        this.scales.solver.x
            .domain([this.zoomedElement.solverDims.x, 1])
            .range([this.zoomedElement.solverDims.x ? this.layout.size.parentNodeWidth :
                0, this.layout.size.solverTree.width
            ]);
        this.scales.solver.y
            .domain([this.zoomedElement.solverDims.y,
            this.zoomedElement.solverDims.y + this.zoomedElement.solverDims.height
            ])
            .range([0, this.layout.size.solverTree.height]);

        if (this.scales.firstRun) { // first run, duplicate what we just calculated
            this.scales.firstRun = false;
            this._preservePreviousScale();

            // Update svg dimensions before size changes
            let outerDims = this.layout.newOuterDims();
            let innerDims = this.layout.newInnerDims();

            this.dom.svgDiv
                .style("width", outerDims.width + this.dims.size.unit)
                .style("height", outerDims.height + this.dims.size.unit);

            this.dom.svg
                .attr("width", outerDims.width)
                .attr("height", outerDims.height)
                .attr("transform", "translate(0 0)");

            this.dom.pTreeGroup
                .attr("height", innerDims.height)
                .attr("width", this.dims.size.partitionTree.width)
                .attr("transform", "translate(0 " + innerDims.margin + ")");

            this.dom.highlightBar
                .attr("height", innerDims.height)
                .attr("width", "8")
                .attr("transform", "translate(" + this.dims.size.partitionTree.width + 1 + " " + innerDims.margin + ")");

            this.dom.n2OuterGroup
                .attr("height", outerDims.height)
                .attr("width", outerDims.height)
                .attr("transform", "translate(" +
                    (this.dims.size.partitionTree.width) + " 0)");

            this.dom.n2InnerGroup.transition(sharedTransition)
                .attr("height", innerDims.height)
                .attr("width", innerDims.height)
                .attr("transform", "translate(" + innerDims.margin + " " + innerDims.margin + ")");

            this.dom.n2BackgroundRect
                .attr("width", innerDims.height)
                .attr("height", innerDims.height)
                .attr("transform", "translate(0 0)");

            this.dom.pSolverTreeGroup
                .attr("height", innerDims.height)
                .attr("transform", "translate(" + (this.dims.size.partitionTree.width +
                    innerDims.margin +
                    innerDims.height +
                    innerDims.margin) + " " +
                    innerDims.margin + ")");

            let offgridHeight = this.dims.size.font + 2;
            this.dom.n2Groups.offgrid.top
                .attr("transform", "translate(" + innerDims.margin + " 0)")
                .attr("width", innerDims.height)
                .attr("height", offgridHeight);

            this.dom.n2Groups.offgrid.bottom
                .attr("transform", "translate(0 " + innerDims.height + offgridHeight + ")")
                .attr("width", outerDims.height)
                .attr("height", offgridHeight);
        }
    }

    _createPartitionCells() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        let selection = this.dom.pTreeGroup.selectAll(".partition_group")
            .data(this.layout.zoomedNodes, function (node) {
                return node.id;
            });

        // Create a new SVG group for each node in zoomedNodes
        let nodeEnter = selection.enter().append("g")
            .attr("class", function (d) {
                return "partition_group " + self.style.getNodeClass(d);
            })
            .attr("transform", function (d) {
                return "translate(" +
                    self.prevScales.model.x(d.prevDims.x) + " " +
                    self.prevScales.model.y(d.prevDims.y) + ")";
            })
            .on("click", function (d) {
                if (self.ui.nodeInfoBox.hidden) { self.ui.leftClick(d); } // Zoom if not in info panel mode
                else { // Pin/unpin the info panel
                    self.ui.nodeInfoBox.togglePin();
                    self.ui.nodeInfoBox.update(d3.event, d, d3.select(this).select('rect').style('fill'));
                }
            })
            .on("contextmenu", function (d) {
                self.ui.rightClick(d, this);
            })
            .on("mouseover", function (d) {
                self.ui.nodeInfoBox.update(d3.event, d, d3.select(this).select('rect').style('fill'));
            })
            .on("mouseleave", function (d) {
                self.ui.nodeInfoBox.clear();
            })
            .on("mousemove", function () {
                self.ui.nodeInfoBox.move(d3.event);
            });

        nodeEnter.append("rect")
            .attr("width", function (d) {
                return d.prevDims.width * self.prevTransitCoords.model.x;
            })
            .attr("height", function (d) {
                return d.prevDims.height * self.prevTransitCoords.model.y;
            })
            .attr("id", function (d) {
                return d.absPathName.replace(/[\.:]/g, '_');
            })
            .attr('rx', 12)
            .attr('ry', 12);

        nodeEnter.append("text")
            .attr("dy", ".35em")
            .attr("transform", function (d) {
                let anchorX = d.prevDims.width * self.prevTransitCoords.model.x -
                    self.layout.size.rightTextMargin;
                return "translate(" + anchorX + " " +
                    (d.prevDims.height * self.prevTransitCoords.model.y / 2) + ")";
            })
            .style("opacity", function (d) {
                if (d.depth < self.zoomedElement.depth) return 0;
                return d.textOpacity;
            })
            .text(self.layout.getText.bind(self.layout));

        return {
            'selection': selection,
            'nodeEnter': nodeEnter
        };
    }

    _setupPartitionTransition(d3Refs) {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        this.dom.clips.partitionTree
            .transition(sharedTransition)
            .attr('height', this.dims.size.partitionTree.height);

        let nodeUpdate = d3Refs.nodeEnter.merge(d3Refs.selection)
            .transition(sharedTransition)
            .attr("class", function (d) {
                return "partition_group " + self.style.getNodeClass(d);
            })
            .attr("transform", function (d) {
                return "translate(" + self.scales.model.x(d.dims.x) + " " +
                    self.scales.model.y(d.dims.y) + ")";
            });

        nodeUpdate.select("rect")
            .attr("width", function (d) {
                return d.dims.width * self.transitCoords.model.x;
            })
            .attr("height", function (d) {
                return d.dims.height * self.transitCoords.model.y;
            })
            .attr('rx', 12)
            .attr('ry', 12);

        nodeUpdate.select("text")
            .attr("transform", function (d) {
                let anchorX = d.dims.width * self.transitCoords.model.x -
                    self.layout.size.rightTextMargin;
                return "translate(" + anchorX + " " + (d.dims.height *
                    self.transitCoords.model.y / 2) + ")";
            })
            .style("opacity", function (d) {
                if (d.depth < self.zoomedElement.depth) return 0;
                return d.textOpacity;
            })
            .text(self.layout.getText.bind(self.layout));
    }

    _runPartitionTransition(selection) {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        // Transition exiting nodes to the parent's new position.
        let nodeExit = selection.exit().transition(sharedTransition)
            .attr("transform", function (d) {
                return "translate(" + self.scales.model.x(d.dims.x) + "," +
                    self.scales.model.y(d.dims.y) + ")";
            })
            .remove();

        nodeExit.select("rect")
            .attr("width", function (d) {
                return d.dims.width * self.transitCoords.model.x;
            })
            .attr("height", function (d) {
                return d.dims.height * self.transitCoords.model.y;
            });

        nodeExit.select("text")
            .attr("transform", function (d) {
                let anchorX = d.dims.width * self.transitCoords.model.x -
                    self.layout.size.rightTextMargin;
                return "translate(" + anchorX + "," + (d.dims.height *
                    self.transitCoords.model.y / 2) + ")";
            })
            .style("opacity", 0);
    }

    _createSolverCells() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        let selection = self.dom.pSolverTreeGroup.selectAll(".solver_group")
            .data(self.layout.zoomedSolverNodes, function (d) {
                return d.id;
            });

        let nodeEnter = selection.enter().append("svg:g")
            .attr("class", function (d) {
                let solver_class = self.style.getSolverClass(self.showLinearSolverNames, {
                    'linear': d.linear_solver,
                    'nonLinear': d.nonlinear_solver
                });
                return solver_class + " solver_group " + self.style.getNodeClass(d);
            })
            .attr("transform", function (d) {
                let x = 1.0 - d.prevSolverDims.x - d.prevSolverDims.width;
                // The magic for reversing the blocks on the right side
                // The solver tree goes from the root on the right and expands to the left
                return "translate(" + self.prevScales.solver.x(x) + "," +
                    self.prevScales.solver.y(d.prevSolverDims.y) + ")";
            })
            .on("click", function (d) {
                if (self.ui.nodeInfoBox.hidden) { self.ui.leftClick(d); } // Zoom if not in info panel mode
                else { // Pin/unpin the info panel
                    self.ui.nodeInfoBox.togglePin();
                    self.ui.nodeInfoBox.update(d3.event, d, d3.select(this).select('rect').style('fill'));
                }
            })
            .on("contextmenu", function (d) {
                self.ui.rightClick(d, this);
            })
            .on("mouseover", function (d) {
                self.ui.nodeInfoBox.update(d3.event, d, d3.select(this).select('rect').style('fill'))

                if (self.model.abs2prom != undefined) {
                    if (d.isInput()) {
                        return self.dom.toolTip.text(self.model.abs2prom.input[d.absPathName])
                            .style("visibility", "visible");
                    }
                    if (d.isOutput()) {
                        return self.dom.toolTip.text(self.model.abs2prom.output[d.absPathName])
                            .style("visibility", "visible");
                    }
                }
            })
            .on("mouseleave", function (d) {
                self.ui.nodeInfoBox.clear();

                if (self.model.abs2prom != undefined) {
                    self.dom.toolTip.style("visibility", "hidden");
                }
            })
            .on("mousemove", function () {
                self.ui.nodeInfoBox.move(d3.event);

                if (self.model.abs2prom != undefined) {
                    self.dom.toolTip.style("top", (d3.event.pageY - 30) + "px")
                        .style("left", (d3.event.pageX + 5) + "px");
                }
            });

        nodeEnter.append("svg:rect")
            .attr("width", function (d) {
                return d.prevSolverDims.width * self.prevTransitCoords.solver.x;
            })
            .attr("height", function (d) {
                return d.prevSolverDims.height * self.prevTransitCoords.solver.y;
            })
            .attr("id", function (d) {
                return d.absPathName.replace(/\./g, '_');
            });

        nodeEnter.append("svg:text")
            .attr("dy", ".35em")
            .attr("transform", function (d) {
                let anchorX = d.prevSolverDims.width * self.prevTransitCoords.solver.x -
                    self.layout.size.rightTextMargin;
                return "translate(" + anchorX + "," + d.prevSolverDims.height *
                    self.prevTransitCoords.solver.y / 2 + ")";
            })
            .style("opacity", function (d) {
                if (d.depth < self.zoomedElement.depth) return 0;
                return d.textOpacity;
            })
            .text(self.layout.getSolverText.bind(self.layout));

        return ({
            'selection': selection,
            'nodeEnter': nodeEnter
        });
    }

    _setupSolverTransition(d3Refs) {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        this.dom.clips.solverTree
            .transition(sharedTransition)
            .attr('height', this.dims.size.solverTree.height);

        let nodeUpdate = d3Refs.nodeEnter.merge(d3Refs.selection)
            .transition(sharedTransition)
            .attr("class", function (d) {
                let solver_class = self.style.getSolverClass(self.showLinearSolverNames, {
                    'linear': d.linear_solver,
                    'nonLinear': d.nonlinear_solver
                });
                return solver_class + " solver_group " + self.style.getNodeClass(d);
            })
            .attr("transform", function (d) {
                let x = 1.0 - d.solverDims.x - d.solverDims.width;
                // The magic for reversing the blocks on the right side

                return "translate(" + self.scales.solver.x(x) + "," +
                    self.scales.solver.y(d.solverDims.y) + ")";
            });

        nodeUpdate.select("rect")
            .attr("width", function (d) {
                return d.solverDims.width * self.transitCoords.solver.x;
            })
            .attr("height", function (d) {
                return d.solverDims.height * self.transitCoords.solver.y;
            })
            .attr('rx', 12)
            .attr('ry', 12);

        nodeUpdate.select("text")
            .attr("transform", function (d) {
                let anchorX = d.solverDims.width * self.transitCoords.solver.x -
                    self.layout.size.rightTextMargin;
                return "translate(" + anchorX + "," + d.solverDims.height *
                    self.transitCoords.solver.y / 2 + ")";
            })
            .style("opacity", function (d) {
                if (d.depth < self.zoomedElement.depth) return 0;
                return d.textOpacity;
            })
            .text(self.layout.getSolverText.bind(self.layout));
    }

    _runSolverTransition(selection) {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        // Transition exiting nodes to the parent's new position.
        let nodeExit = selection.exit()
            .transition(sharedTransition)
            .attr("transform", function (d) {
                return "translate(" + self.scales.solver.x(d.solverDims.x) + "," +
                    self.scales.solver.y(d.solverDims.y) + ")";
            })
            .remove();

        nodeExit.select("rect")
            .attr("width", function (d) {
                return d.solverDims.width * self.transitCoords.solver.x;
            })
            .attr("height", function (d) {
                return d.solverDims.height * self.transitCoords.solver.y;
            });

        nodeExit.select("text")
            .attr("transform", function (d) {
                let anchorX = d.solverDims.width * self.transitCoords.solver.x -
                    self.layout.size.rightTextMargin;
                return "translate(" + anchorX + "," + d.solverDims.height *
                    self.transitCoords.solver.y / 2 + ")";
            })
            .style("opacity", 0);
    }

    /** Remove all rects in the highlight bar */
    clearHighlights() {
        const selection = this.dom.highlightBar.selectAll('rect');
        const size = selection.size();
        debugInfo(`clearHighlights: Removing ${size} highlights`);
        selection.remove();
    }

    /** Remove all pinned arrows */
    clearArrows() {
        this.arrowMgr.removeAllPinned();
        this.clearHighlights();
    }

    /** Display connection arrows for all visible inputs/outputs */
    showAllArrows() {
        for (const row in this.matrix.grid) {
            const cell = this.matrix.grid[row][row]; // Diagonal cells only
            this.matrix.drawOnDiagonalArrows(cell);
            this.arrowMgr.togglePin(cell.id, true);
        }
    }

    delay(time) {
        return new Promise(function(resolve) { 
            setTimeout(resolve, time)
        });
     }

    /** Display an animation while the transition is in progress */
    showWaiter() {
        this.dom.waiter.attr('class', 'show');

    }

    /** Hide the animation after the transition completes */
    hideWaiter() {
        this.dom.waiter.attr('class', 'no-show');
    }

    /**
     * Refresh the diagram when something has visually changed.
     * @param {Boolean} [computeNewTreeLayout = true] Whether to rebuild the layout and
     *  matrix objects.
     */
    async update(computeNewTreeLayout = true) {
        this.showWaiter();
        await this.delay(100);

        this.ui.update();
        this.search.update(this.zoomedElement, this.model.root);

        // Compute the new tree layout if necessary.
        if (computeNewTreeLayout) {
            this.layout = new N2Layout(this.model, this.zoomedElement,
                this.showLinearSolverNames, this.dims);

            this.ui.updateClickedIndices();

            this.matrix = new N2Matrix(this.model, this.layout,
                this.dom.n2Groups, this.arrowMgr, this.ui.lastClickWasLeft,
                this.ui.findRootOfChangeFunction, this.matrix.nodeSize);
        }

        this._updateScale();
        this.layout.updateTransitionInfo(this.dom, this.transitionStartDelay, this.manuallyResized);

        let d3PartRefs = this._createPartitionCells();
        this._setupPartitionTransition(d3PartRefs);
        this._runPartitionTransition(d3PartRefs.selection);

        let d3SolverRefs = this._createSolverCells();
        this._setupSolverTransition(d3SolverRefs);
        this._runSolverTransition(d3SolverRefs.selection);

        this.arrowMgr.transition(this.matrix);
        this.matrix.draw();

        if (!d3.selection.prototype.transitionAllowed) this.hideWaiter();
    }

    /**
     * Updates the intended dimensions of the diagrams and font, but does
     * not perform rendering itself.
     * @param {number} height The base height of the diagram without margins.
     * @param {number} fontSize The new size of the font.
     */
    updateSizes(height, fontSize) {
        let gapSize = fontSize + 4;

        this.dims.size.n2matrix.margin = gapSize;
        this.dims.size.partitionTreeGap = gapSize;

        this.dims.size.n2matrix.height =
            this.dims.size.n2matrix.width = // Match base height, keep it looking square
            this.dims.size.partitionTree.height =
            this.dims.size.solverTree.height = height;

        this.dims.size.font = fontSize;
    }

    /**
     * Adjust the height and corresponding width of the diagram based on user input.
     * @param {number} height The new height in pixels.
     */
    verticalResize(height) {
        // Don't resize if the height didn't actually change:
        if (this.dims.size.partitionTree.height == height) return;

        if (!this.manuallyResized) {
            height = this.layout.calcFitDims().height;
        }

        this.updateSizes(height, this.dims.size.font);

        N2TransitionDefaults.duration = N2TransitionDefaults.durationFast;
        this.update();
    }

    /**
     * Adjust the font size of all text in the diagram based on user input.
     * @param {number} fontSize The new font size in pixels.
     */
    fontSizeSelectChange(fontSize) {
        N2TransitionDefaults.duration = N2TransitionDefaults.durationFast;
        this.style.updateSvgStyle(fontSize);
        this.update();
    }

    /**
     * Since the matrix can be destroyed and recreated, use this to invoke the callback
     * rather than setting one up that points directly to a specific matrix.
     * @param {N2MatrixCell} cell The cell the event occured on.
     */
    mouseOverOnDiagonal(cell) {
        if (this.matrix.cellExists(cell)) {
            this.matrix.mouseOverOnDiagonal(cell);
            this.ui.nodeInfoBox.update(d3.event, cell.obj, cell.color());
        }
    }

    /**
     * Move the node info panel around if it's visible
     * @param {N2MatrixCell} cell The cell the event occured on.
     */
    mouseMoveOnDiagonal(cell) {
        if (this.matrix.cellExists(cell)) {
            this.ui.nodeInfoBox.move(d3.event);
        }
    }

    /**
     * Since the matrix can be destroyed and recreated, use this to invoke the callback
     * rather than setting one up that points directly to a specific matrix.
     */
    mouseOverOffDiagonal(cell) {
        if (this.matrix.cellExists(cell)) {
            this.matrix.mouseOverOffDiagonal(cell);
        }
    }

    /** When the mouse leaves a cell, remove all temporary arrows and highlights. */
    mouseOut() {
        this.arrowMgr.removeAllHovered();
        this.clearHighlights();
        d3.selectAll("div.offgrid").style("visibility", "hidden").html('');

        this.ui.nodeInfoBox.clear();
    }

    /**
     * When the mouse is left-clicked on a cell, change their CSS class
     * so they're not removed when the mouse moves out. Or, if in info panel
     * mode, pin the info panel.
     * @param {N2MatrixCell} cell The cell the event occured on.
     */
    mouseClick(cell) {
        if (this.ui.nodeInfoBox.hidden) { // If not in info-panel mode, pin/unpin arrows
            this.arrowMgr.togglePin(cell.id);
        }
        else { // Pin/unpin the info panel
            this.ui.nodeInfoBox.togglePin();
            this.ui.nodeInfoBox.update(d3.event, cell.obj, cell.color());
        }
    }

    /**
     * Place member mouse callbacks in an object for easy reference.
     * @returns {Object} Object containing each of the functions.
     */
    getMouseFuncs() {
        let self = this;

        let mf = {
            'overOffDiag': self.mouseOverOffDiagonal.bind(self),
            'overOnDiag': self.mouseOverOnDiagonal.bind(self),
            'moveOnDiag': self.mouseMoveOnDiagonal.bind(self),
            'out': self.mouseOut.bind(self),
            'click': self.mouseClick.bind(self)
        }

        return mf;
    }

    /**
     * Recurse through the model, and determine whether a group/component is
     * minimized or manually expanded, or an input/output hidden. If it is,
     * add it to the hiddenList array, and optionally reset its state.
     * @param {Object[]} hiddenList The provided array to populate.
     * @param {Boolean} reveal If true, make the node visible.
     * @param {N2TreeNode} node The current node to operate on.
     */
    findAllHidden(hiddenList, reveal = false, node = this.model.root) {
        if (!node.isVisible() || node.manuallyExpanded) {
            hiddenList.push({
                'node': node,
                'isMinimized': node.isMinimized,
                'varIsHidden': node.varIsHidden,
                'manuallyExpanded': node.manuallyExpanded
            })

            if (reveal) {
                node.isMinimized = false;
                node.varIsHidden = false;
                node.manuallyExpanded = false;
            }
        }

        if (node.hasChildren()) {
            for (const child of node.children) {
                this.findAllHidden(hiddenList, reveal, child);
            }
        }
    }

    /**
     * Restore the minimized/hidden value to all the specified nodes.
     * @param {Object[]} hiddenList The list of preserved objects
     * @param {N2TreeNode} node The current node to operate on.
    */
    resetAllHidden(hiddenList, node = this.model.root) {
        if (!hiddenList) return;

        const foundEntry = hiddenList.find(item => item.node === node);

        if (!foundEntry) { // Not found, reset values to default
            node.isMinimized = false;
            node.varIsHidden = false;
            node.manuallyExpanded = false;
        }
        else { // Found, restore values
            node.isMinimized = foundEntry.isMinimized;
            node.varIsHidden = foundEntry.varIsHidden;
            node.manuallyExpanded = foundEntry.manuallyExpanded;
        }

        if (node.hasChildren()) {
            for (const child of node.children) {
                this.resetAllHidden(hiddenList, child);
            }
        }
    }

    /** Unset all manually-selected node states and zoom to the root element */
    reset() {
        this.resetAllHidden([]);
        this.updateZoomedElement(this.model.root);
        N2TransitionDefaults.duration = N2TransitionDefaults.durationFast;
        this.update();
    }

    /**
     * Set the node as not minimized and manually expanded, as well as
     * all children.
     * @param {N2TreeNode} startNode The node to begin from.
     */
    manuallyExpandAll(startNode) {
        startNode.isMinimized = false;
        startNode.manuallyExpanded = true;

        if (startNode.hasChildren()) {
            for (let child of startNode.children) {
                this.manuallyExpandAll(child);
            }
        }
    }

    /**
     * Set all the children of the specified node as minimized and not manually expanded.
     * @param {N2TreeNode} startNode The node to begin from.
     * @param {Boolean} [initialNode = true] Indicate the starting node.
     */
    minimizeAll(startNode, initialNode = true) {
        if (!initialNode) {
            startNode.isMinimized = true;
            startNode.manuallyExpanded = false;
        }

        if (startNode.hasChildren()) {
            for (let child of startNode.children) {
                this.minimizeAll(child, false);
            }
        }
    }

    /**
     * Recursively minimize non-input nodes to the specified depth.
     * @param {N2TreeNode} node The node to work on.
     */
    _minimizeToDepth(node) {
        if (node.isInputOrOutput()) {
            return;
        }

        if (node.depth < this.chosenCollapseDepth) {
            node.isMinimized = false;
            node.manuallyExpanded = true;
        }
        else {
            node.isMinimized = true;
            node.manuallyExpanded = false;
        }

        if (node.hasChildren()) {
            for (let child of node.children) {
                this._minimizeToDepth(child);
            }
        }
    }

    /**
     * Set the new depth to collapse to and perform the operation.
     * @param {Number} depth If the node's depth is the same or more, collapse it.
     */
    minimizeToDepth(depth) {
        this.chosenCollapseDepth = depth;

        if (this.chosenCollapseDepth > this.zoomedElement.depth)
            this._minimizeToDepth(this.model.root);
    }
}

</script>

    <script type="text/javascript">
/**
 * Manage info for each node metadata property
 * @typedef InfoPropDefault
 * @property {String} key The identifier of the property.
 * @property {String} desc The description (label) to display.
 * @property {Boolean} capitalize Whether to capitialize every word in the desc.
 */
class InfoPropDefault {
    constructor(key, desc, capitalize = false) {
        this.key = key;
        this.desc = desc;
        this.capitalize = capitalize;
    }

    /** Return the same message since this is the base class */
    output(msg) { return msg; }
}

/**
 * Outputs a Yes or No to display. 
 * @typedef InfoPropYesNo
 */
class InfoPropYesNo extends InfoPropDefault {
    constructor(key, desc, capitalize = false) {
        super(key, desc, capitalize);
    }

    /** Return Yes or No when given True or False */
    output(boolVal) { return boolVal ? 'Yes' : 'No'; }
}

/**
 * Rename inputs to inputs and outputs to outputs. 
 * @typedef InfoPropYesNo
 */
class InfoUpdateType extends InfoPropDefault {
    constructor(key, desc, capitalize = false) {
        super(key, desc, capitalize);
    }

    /** Replace the old terms with new ones */
    output(msg) {
        return msg
            .replace(/input/, 'input')
            .replace(/output/, 'output')
            .replace('_', ' ');
    }
}

/**
 * Manage a table containing all available metadata properties for
 * the currently active node, as well as whether the table is
 * visible or not.
 * @typedef NodeInfo
 */
class NodeInfo {
    /**
     * Build a list of the properties we care about and set up
     * references to the HTML elements.
     * @param {Object} abs2prom Object containing promoted variable names.
     */
    constructor(abs2prom) {
        this.propList = [
            new InfoPropDefault('absPathName', 'Absolute Name'),
            new InfoPropDefault('class', 'Class'),
            new InfoUpdateType('type', 'Type', true),
            new InfoPropDefault('dtype', 'DType'),
            new InfoPropDefault('subsystem_type', 'Subsystem Type', true),
            new InfoPropDefault('component_type', 'Component Type', true),
            new InfoPropYesNo('implicit', 'Implicit'),
            new InfoPropYesNo('is_parallel', 'Parallel'),
            new InfoPropDefault('linear_solver', 'Linear Solver'),
            new InfoPropDefault('nonlinear_solver', 'Non-Linear Solver')
        ];

        this.abs2prom = abs2prom;
        this.table = d3.select('#node-info-table');
        this.container = d3.select('#node-info-container');
        this.thead = this.table.select('thead');
        this.tbody = this.table.select('tbody');
        this.toolbarButton = d3.select('#info-button');
        this.hidden = true;
        this.pinned = false;

        const self = this;
        this.pinButton = d3.select('#node-info-pin')
            .on('click', e => { self.unpin(); })
    }

    /** Make the info box visible if it's hidden */
    show() {
        this.toolbarButton.attr('class', 'fas icon-info-circle active-tab-icon');
        this.hidden = false;
        d3.select('#all_pt_n2_content_div').classed('node-data-cursor', true);
    }

    /** Make the info box hidden if it's visible */
    hide() {
        this.toolbarButton.attr('class', 'fas icon-info-circle');
        this.hidden = true;
        d3.select('#all_pt_n2_content_div').classed('node-data-cursor', false);
    }

    /** Toggle the visibility setting */
    toggle() {
        if (this.hidden) this.show();
        else this.hide();
    }

    pin() { 
        this.pinned = true;
        this.pinButton.attr('class', 'info-visible');
    }
    
    unpin() {
        this.pinned = false;
        this.pinButton.attr('class', 'info-hidden');
        this.clear();
    }

    togglePin() {
        if (this.pinned) this.unpin();
        else this.pin();
    }

    _addPropertyRow(label, val, capitalize = false) {
        const newRow = this.tbody.append('tr');

        newRow.append('th')
            .attr('scope', 'row')
            .text(label);

        const td = newRow.append('td')
            .text(val);

        if (capitalize) td.attr('class', 'caps');
    }

    /**
     * Iterate over the list of known properties and display them
     * if the specified object contains them.
     * @param {Object} event The related event so we can get position.
     * @param {N2TreeNode} obj The node to examine.
     * @param {N2TreeNode} color The color to make the title bar.
     */
    update(event, obj, color = '#42926b') {
        if (this.hidden || this.pinned) return;

        this.clear();
        // Put the name in the title
        this.table.select('thead th')
            .style('background-color', color)
            .text(obj.name);

        this.table.select('tfoot th')
            .style('background-color', color);

        if (this.abs2prom) {
            if (obj.isInput()) {
                this._addPropertyRow('Promoted Name', this.abs2prom.input[obj.absPathName]);
            }
            else if (obj.isOutput()) {
                this._addPropertyRow('Promoted Name', this.abs2prom.output[obj.absPathName]);
            }
        }

        if (DebugFlags.info && obj.hasChildren()) {
            this._addPropertyRow('Children', obj.children.length);
            this._addPropertyRow('Descendants', obj.numDescendants);
            this._addPropertyRow('Leaves', obj.numLeaves);
            this._addPropertyRow('Manually Expanded', obj.manuallyExpanded.toString())
        }

        for (const prop of this.propList) {
            if (obj.propExists(prop.key) && obj[prop.key] != '') {
                this._addPropertyRow(prop.desc, prop.output(obj[prop.key]), prop.capitalize)
            }
        }

        // Solidify the size of the table after populating so that
        // it can be positioned reliably by move().
        this.table
            .style('width', this.table.node().scrollWidth + 'px')
            .style('height', this.table.node().scrollHeight + 'px')

        this.move(event);
        this.container.attr('class', 'info-visible');
    }

    /** Wipe the contents of the table body */
    clear() {
        if (this.hidden || this.pinned) return;
        this.container
            .attr('class', 'info-hidden')
            .style('width', 'auto')
            .style('height', 'auto');

        this.table
            .style('width', 'auto')
            .style('height', 'auto');

        this.tbody.html('');
    }

    /**
     * Relocate the table to a position near the mouse
     * @param {Object} event The triggering event containing the position.
     */
    move(event) {
        if (this.hidden || this.pinned) return;
        const offset = 30;

        // Mouse is in left half of window, put box to right of mouse
        if (event.clientX < window.innerWidth / 2) {
            this.container.style('right', 'auto');
            this.container.style('left', (event.clientX + offset) + 'px')
        }
        // Mouse is in right half of window, put box to left of mouse
        else {
            this.container.style('left', 'auto');
            this.container.style('right', (window.innerWidth - event.clientX + offset) + 'px')
        }

        // Mouse is in top half of window, put box below mouse
        if (event.clientY < window.innerHeight / 2) {
            this.container.style('bottom', 'auto');
            this.container.style('top', (event.clientY - offset) + 'px')
        }
        // Mouse is in bottom half of window, put box above mouse
        else {
            this.container.style('top', 'auto');
            this.container.style('bottom', (window.innerHeight - event.clientY - offset) + 'px')
        }
    }
}

/**
 * Handle input events for the matrix and toolbar.
 * @typedef N2UserInterface
 * @property {N2Diagram} n2Diag Reference to the main diagram.
 * @property {N2TreeNode} leftClickedNode The last node that was left-clicked.
 * @property {N2TreeNode} rightClickedNode The last node that was right-clicked, if any.
 * @property {Boolean} lastClickWasLeft True is last mouse click was left, false if right.
 * @property {Boolean} leftClickIsForward True if the last node clicked has a greater depth
 *  than the current zoomed element.
 * @property {Array} backButtonHistory The stack of forward-navigation zoomed elements.
 * @property {Array} forwardButtonHistory The stack of backward-navigation zoomed elements.
 */

class N2UserInterface {
    /**
     * Initialize properties, set up the collapse-depth menu, and set up other
     * elements of the toolbar.
     * @param {N2Diagram} n2Diag A reference to the main diagram.
     */
    constructor(n2Diag) {
        this.n2Diag = n2Diag;

        this.leftClickedNode = document.getElementById('ptN2ContentDivId');
        this.rightClickedNode = null;
        this.lastClickWasLeft = true;
        this.leftClickIsForward = true;
        this.findRootOfChangeFunction = null;
        this.callSearchFromEnterKeyPressed = false;

        this.backButtonHistory = [];
        this.forwardButtonHistory = [];

        this._setupCollapseDepthElement();
        this.updateClickedIndices();
        this._setupSearch();
        this._setupResizerDrag();
        this._setupWindowResizer();

        this.legend = new N2Legend(this.n2Diag.modelData);
        this.nodeInfoBox = new NodeInfo(this.n2Diag.model.abs2prom);
        this.toolbar = new N2Toolbar(this);
    }

    /** Set up the menu for selecting an arbitrary depth to collapse to. */
    _setupCollapseDepthElement() {
        let self = this;

        let collapseDepthElement = this.n2Diag.dom.parentDiv.querySelector(
            '#depth-slider'
        );

        collapseDepthElement.max = this.n2Diag.model.maxDepth - 1;
        collapseDepthElement.value = collapseDepthElement.max;

        collapseDepthElement.onmouseup = function (e) {
            const modelDepth = parseInt(e.target.value);
            self.collapseToDepthSelectChange(modelDepth);
        };
    }

    /** Set up event handlers for grabbing the bottom corner and dragging */
    _setupResizerDrag() {
        const handle = d3.select('#n2-resizer-handle');
        const box = d3.select('#n2-resizer-box');
        const body = d3.select('body');

        handle.on('mousedown', e => {
            box
                .style('top', n2Diag.layout.gapSpace)
                .style('bottom', n2Diag.layout.gapSpace);

            handle.attr('class', 'active-resizer-handle');
            box.attr('class', 'active-resizer-box');

            const startPos = {
                'x': d3.event.clientX,
                'y': d3.event.clientY
            };
            const startDims = {
                'width': parseInt(box.style('width')),
                'height': parseInt(box.style('height'))
            };
            const offset = {
                'x': startPos.x - startDims.width,
                'y': startPos.y - startDims.height
            };
            let newDims = {
                'x': startDims.width,
                'y': startDims.height
            };

            handle.html(Math.round(newDims.x) + ' x ' + newDims.y);

            body.style('cursor', 'nwse-resize')
                .on('mouseup', e => {
                    n2Diag.manuallyResized = true;

                    // Update the slider value and display
                    const defaultHeight = window.innerHeight * .95;
                    const newPercent = Math.round((newDims.y / defaultHeight) * 100);
                    d3.select('#model-slider').node().value = newPercent;
                    d3.select('#model-slider-label').html(newPercent + "%");

                    // Perform the actual resize
                    n2Diag.verticalResize(newDims.y);

                    box.style('width', null).style('height', null);

                    // Turn off the resizing box border and handle
                    handle.attr('class', 'inactive-resizer-handle');
                    box.attr('class', 'inactive-resizer-box');

                    // Get rid of the drag event handlers
                    body.style('cursor', 'default')
                        .on('mousemove', null)
                        .on('mouseup', null);
                })
                .on('mousemove', e => {
                    const newHeight = d3.event.clientY - offset.y;
                    if (newHeight + n2Diag.layout.gapDist * 2 >= window.innerHeight * .5) {
                        newDims = {
                            'x': d3.event.clientX - offset.x,
                            'y': newHeight
                        };

                        // Maintain the ratio by only resizing in the least moved direction
                        // and resizing the other direction by a fraction of that
                        if (newDims.x < newDims.y) {
                            newDims.y = n2Diag.layout.calcHeightBasedOnNewWidth(newDims.x);
                        }
                        else {
                            newDims.x = n2Diag.layout.calcWidthBasedOnNewHeight(newDims.y);
                        }

                        box
                            .style('width', newDims.x + 'px')
                            .style('height', newDims.y + 'px');

                        handle.html(Math.round(newDims.x) + ' x ' + newDims.y);
                    }
                });

            d3.event.preventDefault();
        });

    }

    /** Respond to window resize events if the diagram hasn't been manually sized */
    _setupWindowResizer() {
        const self = this;
        const n2Diag = self.n2Diag;
        this.pixelRatio = window.devicePixelRatio;

        self.resizeTimeout = null;
        d3.select(window).on('resize', function () {
            const newPixelRatio = window.devicePixelRatio;

            // If the browser window itself is zoomed, don't do anything
            if (newPixelRatio != self.pixelRatio) {
                self.pixelRatio = newPixelRatio;
                return;
            }

            if (!n2Diag.manuallyResized) {
                clearTimeout(self.resizeTimeout);
                self.resizeTimeout =
                    setTimeout(function () {
                        n2Diag.verticalResize(window.innerHeight * .95);
                    }, 200);
            }
        })
    }

    /**
     * Make sure the clicked node is deeper than the zoomed node, that
     * it's not the root node, and that it actually has children.
     * @param {N2TreeNode} node The right-clicked node to check.
     */
    isCollapsible(node) {
        return (node.depth > this.n2Diag.zoomedElement.depth &&
            node.type !== 'root' && node.hasChildren());
    }

    /**
     * When a node is right-clicked or otherwise targeted for collapse, make sure it
     * it's allowed, then set the node as minimized and update the diagram drawing.
     */
    collapse() {
        testThis(this, 'N2UserInterface', 'collapse');

        let node = this.rightClickedNode;

        if (this.isCollapsible(node)) {

            if (this.collapsedRightClickNode !== undefined) {
                this.rightClickedNode = this.collapsedRightClickNode;
                this.collapsedRightClickNode = undefined;
            }

            this.findRootOfChangeFunction =
                this.findRootOfChangeForRightClick.bind(this);

            N2TransitionDefaults.duration = N2TransitionDefaults.durationFast;
            this.lastClickWasLeft = false;
            node.minimize();
            this.n2Diag.update();
        }
    }

    /**
     * When a node is right-clicked, collapse it if it's allowed.
     * @param {N2TreeNode} node The node that was right-clicked.
     */
    rightClick(node) {
        testThis(this, 'N2UserInterface', 'rightClick');

        d3.event.preventDefault();
        d3.event.stopPropagation();

        if (node.isMinimized) {
            this.rightClickedNode = node;
            this.addBackButtonHistory();
            node.manuallyExpanded = true;
            this._uncollapse(node);
            this.n2Diag.update();
        }
        else if (this.isCollapsible(node)) {
            this.rightClickedNode = node;
            node.collapsable = true;

            this.addBackButtonHistory();
            node.manuallyExpanded = false;
            this.collapse();
        }
    }

    /**
     * Update states as if a left-click was performed, which may or may not have
     * actually happened.
     * @param {N2TreeNode} node The node that was targetted.
     */
    _setupLeftClick(node) {
        this.leftClickedNode = node;
        this.lastClickWasLeft = true;
        if (this.leftClickedNode.depth > this.n2Diag.zoomedElement.depth) {
            this.leftClickIsForward = true; // forward
        }
        else if (this.leftClickedNode.depth < this.n2Diag.zoomedElement.depth) {
            this.leftClickIsForward = false; // backwards
        }
        this.n2Diag.updateZoomedElement(node);
        N2TransitionDefaults.duration = N2TransitionDefaults.durationFast;
    }

    /**
     * React to a left-clicked node by zooming in on it.
     * @param {N2TreeNode} node The targetted node.
     */
    leftClick(node) {
        // Don't do it if the node is already zoomed
        if (node === this.n2Diag.zoomedElement) return;

        testThis(this, 'N2UserInterface', 'leftClick');
        d3.event.preventDefault();
        d3.event.stopPropagation();

        if (!node.hasChildren() || node.isInput()) return;
        if (d3.event.button != 0) return;
        this.addBackButtonHistory();
        node.expand();
        node.manuallyExpanded = true;
        this._setupLeftClick(node);

        this.n2Diag.update();
    }

    /**
     * Set up for an animated transition by setting and remembering where things were.
     */
    updateClickedIndices() {
        enterIndex = exitIndex = 0;

        if (this.lastClickWasLeft) {
            let lcRootIndex = (! this.leftClickedNode || ! this.leftClickedNode.rootIndex)? 0 :
                this.leftClickedNode.rootIndex;

            if (this.leftClickIsForward) {
                exitIndex = lcRootIndex - this.n2Diag.zoomedElementPrev.rootIndex;
            }
            else {
                enterIndex = this.n2Diag.zoomedElementPrev.rootIndex - lcRootIndex;
            }
        }
    }

    /**
     * Preserve the current zoomed element and state of all hidden elements.
     * @param {Boolean} clearForward If true, erase the forward history.
     */
    addBackButtonHistory(clearForward = true) {
        let formerHidden = [];
        this.n2Diag.findAllHidden(formerHidden, false);

        this.backButtonHistory.push({
            'node': this.n2Diag.zoomedElement,
            'hidden': formerHidden
        });

        if (clearForward) this.forwardButtonHistory = [];
    }

    /**
     * Preserve the specified node as the zoomed element,
     * and remember the state of all hidden elements.
     * @param {N2TreeNode} node The node to preserve as the zoomed element.
     */
    addForwardButtonHistory(node) {
        let formerHidden = [];
        this.n2Diag.findAllHidden(formerHidden, true);

        this.forwardButtonHistory.push({
            'node': node,
            'hidden': formerHidden
        });
    }

    /**
     * When the back history button is clicked, pop the top node from that
     * history stack, and disable the button if the stack is empty. Find the
     * neared un-minimized node (if not the node itself) and zoom to that.
     * Add the previous zoomed node to the forward history stack.
     */
    backButtonPressed() {
        testThis(this, 'N2UserInterface', 'backButtonPressed');

        if (this.backButtonHistory.length == 0) {
            debugInfo("backButtonPressed(): no items in history");
            return;
        }

        debugInfo("backButtonPressed(): " +
            this.backButtonHistory.length + " items in history");

        const history = this.backButtonHistory.pop();
        const node = history.node;

        // Check to see if the node is a collapsed node or not
        if (node.collapsable) {
            this.leftClickedNode = node;
            this.addForwardButtonHistory(node);
            this.collapse();
        }
        else {
            for (let obj = node; obj != null; obj = obj.parent) {
                //make sure history item is not minimized
                if (obj.isMinimized) return;
            }

            this.addForwardButtonHistory(this.n2Diag.zoomedElement);
            this._setupLeftClick(node);
        }

        this.n2Diag.resetAllHidden(history.hidden);
        this.n2Diag.update();
    }

    /**
     * When the forward history button is clicked, pop the top node from that
     * history stack, and disable the button if the stack is empty. Find the
     * neared un-minimized node (if not the node itself) and zoom to that.
     * Add the previous zoomed node to the back history stack.
     */
    forwardButtonPressed() {
        testThis(this, 'N2UserInterface', 'forwardButtonPressed');

        if (this.forwardButtonHistory.length == 0) {
            debugInfo("forwardButtonPressed(): no items in history");
            return;
        }

        debugInfo("forwardButtonPressed(): " +
            this.forwardButtonHistory.length + " items in history");

        const history = this.forwardButtonHistory.pop();
        const node = history.node;

        d3.select('#redo-graph').classed('disabled-button',
            (this.forwardButtonHistory.length == 0));

        for (let obj = node; obj != null; obj = obj.parent) {
            // make sure history item is not minimized
            if (obj.isMinimized) return;
        }

        this.addBackButtonHistory(false);
        this._setupLeftClick(node);

        this.n2Diag.resetAllHidden(history.hidden);
        this.n2Diag.update();
    }

    /**
     * When the last event to change the zoom level was a right-click,
     * return the targetted node. Called during drawing/transition.
     * @returns The last right-clicked node.
     */
    findRootOfChangeForRightClick() {
        return this.rightClickedNode;
    }

    /**
     * When the last event to change the zoom level was the selection
     * from the collapse depth menu, return the node with the
     * appropriate depth.
     * @returns The node that has the selected depth if it exists.
     */
    findRootOfChangeForCollapseDepth(node) {
        for (let obj = node; obj != null; obj = obj.parent) {
            //make sure history item is not minimized
            if (obj.depth == this.n2Diag.chosenCollapseDepth) return obj;
        }
        return node;
    }

    /**
     * When either of the collapse or uncollapse toolbar buttons are
     * pressed, return the parent component of the targetted node if
     * it has one, or the node itself if not.
     * @returns Parent component of output node or node itself.
     */
    findRootOfChangeForCollapseUncollapseOutputs(node) {
        return node.hasOwnProperty('parentComponent') ?
            node.parentComponent :
            node;
    }

    /**
     * When the home button (aka return-to-root) button is clicked, zoom
     * to the root node.
     */
    homeButtonClick() {
        testThis(this, 'N2UserInterface', 'homeButtonClick');

        this.leftClickedNode = this.n2Diag.model.root;
        this.lastClickWasLeft = true;
        this.leftClickIsForward = false;
        this.findRootOfChangeFunction = this.findRootOfChangeForCollapseUncollapseOutputs;
        this.addBackButtonHistory();

        this.n2Diag.reset();
    }

    /**
     * Minimize the specified node and recursively minimize its children.
     * @param {N2TreeNode} node The current node to operate on.
     */
    _collapseOutputs(node) {
        if (node.subsystem_type && node.subsystem_type == 'component') {
            node.isMinimized = true;
        }
        if (node.hasChildren()) {
            for (let child of node.children) {
                this._collapseOutputs(child);
            }
        }
    }

    /**
     * React to a button click and collapse all outputs of the specified node.
     * @param {N2TreeNode} node The initial node, usually the currently zoomed element.
     */
    collapseOutputsButtonClick(startNode) {
        testThis(this, 'N2UserInterface', 'collapseOutputsButtonClick');

        this.addBackButtonHistory();
        this.findRootOfChangeFunction = this.findRootOfChangeForCollapseUncollapseOutputs;
        N2TransitionDefaults.duration = N2TransitionDefaults.durationSlow;
        this.lastClickWasLeft = false;
        this._collapseOutputs(startNode);
        this.n2Diag.update();
    }

    /**
     * Mark this node and all of its children as unminimized/unhidden
     * @param {N2TreeNode} node The node to operate on.
     */
    _uncollapse(node) {
        node.expand();
        node.varIsHidden = false;

        if (node.hasChildren()) {
            for (let child of node.children) {
                this._uncollapse(child);
            }
        }
    }

    /**
     * React to a button click and uncollapse the specified node.
     * @param {N2TreeNode} startNode The initial node.
     */
    uncollapseButtonClick(startNode) {
        testThis(this, 'N2UserInterface', 'uncollapseButtonClick');

        this.addBackButtonHistory();
        this.findRootOfChangeFunction = this.findRootOfChangeForCollapseUncollapseOutputs;
        N2TransitionDefaults.duration = N2TransitionDefaults.durationSlow;
        this.lastClickWasLeft = false;
        this._uncollapse(startNode);
        startNode.manuallyExpanded = true;
        this.n2Diag.update();
    }

    /** Any collapsed nodes are expanded, starting with the specified node. */
    expandAll(startNode) {
        testThis(this, 'N2UserInterface', 'expandAll');

        this.n2Diag.showWaiter();

        this.addBackButtonHistory();
        this.n2Diag.manuallyExpandAll(startNode);

        this.findRootOfChangeFunction = this.findRootOfChangeForCollapseUncollapseOutputs;
        N2TransitionDefaults.duration = N2TransitionDefaults.durationSlow;
        this.lastClickWasLeft = false;
        this.n2Diag.update();
    }

    /** All nodes are collapsed, starting with the specified node. */
    collapseAll(startNode) {
        testThis(this, 'N2UserInterface', 'collapseAll');

        this.addBackButtonHistory();
        this.n2Diag.minimizeAll(startNode);

        this.findRootOfChangeFunction = this.findRootOfChangeForCollapseUncollapseOutputs;
        N2TransitionDefaults.duration = N2TransitionDefaults.durationSlow;
        this.lastClickWasLeft = false;
        this.n2Diag.update();
    }

    /**
     * React to a new selection in the collapse-to-depth drop-down.
     * @param {Number} newChosenCollapseDepth Selected depth to collapse to.
     */
    collapseToDepthSelectChange(newChosenCollapseDepth) {
        testThis(this, 'N2UserInterface', 'collapseToDepthSelectChange');

        this.addBackButtonHistory();
        this.n2Diag.minimizeToDepth(newChosenCollapseDepth);
        this.findRootOfChangeFunction = this.findRootOfChangeForCollapseDepth.bind(
            this
        );
        N2TransitionDefaults.duration = N2TransitionDefaults.durationSlow;
        this.lastClickWasLeft = false;
        this.n2Diag.update();
    }

    /**
     * React to the toggle-solver-name button press and show non-linear if linear
     * is currently shown, and vice-versa.
     */
    toggleSolverNamesCheckboxChange() {
        testThis(this, 'N2UserInterface', 'toggleSolverNamesCheckboxChange');

        this.n2Diag.toggleSolverNameType();
        this.n2Diag.dom.parentDiv.querySelector(
            '#linear-solver-button'
        ).className = !this.n2Diag.showLinearSolverNames ?
                'fas icon-nonlinear-solver solver-button' :
                'fas icon-linear-solver solver-button';

        this.legend.toggleSolvers(this.n2Diag.showLinearSolverNames);

        if (this.legend.shown)
            this.legend.show(
                this.n2Diag.showLinearSolverNames,
                this.n2Diag.style.solvers
            );
        this.n2Diag.update();
    }

    /** React to the toggle legend button, and show or hide the legend below the N2. */
    toggleLegend() {
        testThis(this, 'N2UserInterface', 'toggleLegend');
        this.legend.toggle();

        d3.select('#legend-button').attr('class',
            this.legend.hidden ? 'fas icon-key' : 'fas icon-key active-tab-icon');
    }

    /** Show or hide the node info panel button */
    toggleNodeData() {
        testThis(this, 'N2UserInterface', 'toggleNodeData');

        const infoButton = d3.select('#info-button');
        const nodeData = d3.select('#node-info-table');

        if (nodeData.classed('info-hidden')) {
            nodeData.attr('class', 'info-visible');
            infoButton.attr('class', 'fas icon-info-circle active-tab-icon');
        }
        else {
            nodeData.attr('class', 'info-hidden');
            infoButton.attr('class', 'fas icon-info-circle');
        }
    }

    _setupSearch() {
        let self = this; // For callbacks that change "this". Alternative to using .bind().

        // Keyup so it will be after the input and awesomplete-selectcomplete event listeners
        window.addEventListener(
            'keyup',
            self.searchEnterKeyUpEventListener.bind(self),
            true
        );

        // Keydown so it will be before the input and awesomplete-selectcomplete event listeners
        window.addEventListener(
            'keydown',
            self.searchEnterKeyDownEventListener.bind(self),
            true
        );
    }

    /** Make sure UI controls reflect history and current reality. */
    update() {
        testThis(this, 'N2UserInterface', 'update');

        d3.select('#undo-graph').classed('disabled-button',
            (this.backButtonHistory.length == 0));
        d3.select('#redo-graph').classed('disabled-button',
            (this.forwardButtonHistory.length == 0));
    }

    /** Called when the search button is actually or effectively clicked to start a search. */
    searchButtonClicked() {
        testThis(this, 'N2UserInterface', 'searchButtonClicked');
        this.addBackButtonHistory();
        this.n2Diag.search.performSearch();

        this.findRootOfChangeFunction = this.n2Diag.search.findRootOfChangeForSearch;
        N2TransitionDefaults.duration = N2TransitionDefaults.durationSlow;
        this.lastClickWasLeft = false;
        this.n2Diag.search.updateRecomputesAutoComplete = false;
        this.n2Diag.update();
    }

    /**
     * Called when the enter key is pressed in the search input box.
     * @param {Event} e Object with information about the event.
     */
    searchEnterKeyDownEventListener(e) {
        testThis(this, 'N2UserInterface', 'searchEnterKeyDownEventListener');

        let target = e.target;
        if (target.id == 'awesompleteId') {
            let key = e.which || e.keyCode;
            if (key === 13) {
                // 13 is enter
                this.callSearchFromEnterKeyPressed = true;
            }
        }
    }

    searchEnterKeyUpEventListener(e) {
        testThis(this, 'N2UserInterface', 'searchEnterKeyUpEventListener');

        let target = e.target;
        if (target.id == 'awesompleteId') {
            let key = e.which || e.keyCode;
            if (key == 13) {
                // 13 is enter
                if (this.callSearchFromEnterKeyPressed) {
                    this.searchButtonClicked();
                }
            }
        }
    }
}

</script>
     <script type="text/javascript">
// Constants and default valus
const EMBEDDED = (d3.selectAll("#all_pt_n2_content_div").classed("embedded-n2"));
const ALLOW_PRECOLLAPSE_COUNT = 200; // Consider precollapsing nodes in models larger than this
const PRECOLLAPSE_THRESHOLD = 10; // Pre-collapse nodes with more descendants than this
const _DEFAULT_N2_DIAGRAM_UNIT = 'px';
const _DEFAULT_N2_DIAGRAM_HEIGHT = window.innerHeight * .95;
const _DEFAULT_FONT_SIZE = 11;
const _DEFAULT_GAP_SIZE = _DEFAULT_FONT_SIZE + 4;

defaultDims = {
    'size': {
        'unit': _DEFAULT_N2_DIAGRAM_UNIT,
        'n2matrix': { // Dimensions of N2 matrix diagram
            'height': _DEFAULT_N2_DIAGRAM_HEIGHT,
            'width': _DEFAULT_N2_DIAGRAM_HEIGHT,
            'margin': _DEFAULT_GAP_SIZE
        },
        'partitionTree': { // Dimensions of the tree on the left side of the diagram
            'width': 0,
            'height': _DEFAULT_N2_DIAGRAM_HEIGHT,
        },
        'solverTree': { // Dimensions of the tree on the right side of the diagram
            'width': 0,
            'height': _DEFAULT_N2_DIAGRAM_HEIGHT,
        },
        'font': _DEFAULT_FONT_SIZE,
        'minColumnWidth': 2,
        'rightTextMargin': 8,
        'parentNodeWidth': 30,
        'partitionTreeGap': _DEFAULT_GAP_SIZE, // Pixels between partition tree and N2 matrix
        'svgMargin': 1,
    }
};

Object.freeze(defaultDims);

// TODO: Probably move this into N2Diagram or other class
let N2TransitionDefaults = {
    'startDelay': 100,
    'duration': 1000,
    'durationFast': 1000,
    'durationSlow': 1500,
    'maxNodes': 150
}

let DebugFlags = {
    'timings': false,
    'info': false
}

// Object.freeze(N2TransitionDefaults);

</script>
     <script type="text/javascript">
let sharedTransition = null;

var enterIndex = 0;
var exitIndex = 0;

// The modelData object is generated and populated by n2_viewer.py
var modelData  = ModelData.uncompressModel(compressedModel);
delete compressedModel;

let n2Diag = new N2Diagram(modelData);
let n2MouseFuncs = n2Diag.getMouseFuncs();
n2Diag.update(false);


</script>
